Home/Learn/Hibernate & JPA/@MappedSuperclass

@MappedSuperclass

Intermediate
Inheritance

@MappedSuperclass shares fields across entities without creating a table; ideal for audit fields (createdAt, updatedAt, createdBy) that appear in every entity.

Overview

@MappedSuperclass is a JPA annotation for an abstract base class that contributes mapped fields to its subclass entities without having its own DB table. It is NOT an entity itself — you cannot query it or hold a reference to it polymorphically. The primary use case is sharing common fields like id, createdAt, updatedAt, createdBy across all entities. Combine with Spring Data's AuditingEntityListener for automatic audit field population.

Shared Audit Fields Pattern

Define an abstract @MappedSuperclass with audit fields. All entity subclasses inherit the columns into their own table. Each entity has its own id column; the base class holds the generation strategy.

Java — @MappedSuperclass for audit fields
// Base class — NOT an entity; no table created
@MappedSuperclass
@EntityListeners(AuditingEntityListener.class)   // Spring Data auditing
public abstract class BaseEntity {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    @CreatedDate
    @Column(name = "created_at", nullable = false, updatable = false)
    private LocalDateTime createdAt;

    @LastModifiedDate
    @Column(name = "updated_at", nullable = false)
    private LocalDateTime updatedAt;

    @CreatedBy
    @Column(name = "created_by", updatable = false)
    private String createdBy;

    @LastModifiedBy
    @Column(name = "updated_by")
    private String updatedBy;

    // Getters (no setters for audited fields — populated by Spring)
    public Long getId() { return id; }
    public LocalDateTime getCreatedAt() { return createdAt; }
}

// Entity — inherits all BaseEntity columns into its own table
@Entity
@Table(name = "products")
public class Product extends BaseEntity {
    private String name;
    private BigDecimal price;
}

// Resulting "products" table columns:
// id | created_at | updated_at | created_by | updated_by | name | price

Spring Data Auditing Setup

Enable Spring Data auditing with @EnableJpaAuditing. Provide an AuditorAware<T> bean that returns the current user name from the security context.

Java — Spring Data auditing with AuditorAware
// Enable JPA auditing on main class or @Configuration
@EnableJpaAuditing(auditorAwareRef = "auditorProvider")
@SpringBootApplication
public class App { ... }

// Provide current user from Spring Security
@Bean
public AuditorAware<String> auditorProvider() {
    return () -> Optional.ofNullable(SecurityContextHolder.getContext())
        .map(SecurityContext::getAuthentication)
        .filter(Authentication::isAuthenticated)
        .map(Authentication::getName);
}

// Now @CreatedBy and @LastModifiedBy are auto-populated:
// product.getCreatedBy() → "alice"  (username from SecurityContext)

// For non-Spring Security contexts — provide a static name
@Bean
public AuditorAware<String> auditorProvider() {
    return () -> Optional.of("system");
}

@MappedSuperclass vs @Inheritance

@MappedSuperclass is NOT an inheritance mapping strategy — you cannot query or polymorphically navigate to the superclass. For true polymorphic queries use @Inheritance (SINGLE_TABLE, JOINED, TABLE_PER_CLASS).

Java — @MappedSuperclass vs @Inheritance
// @MappedSuperclass — NO polymorphic query possible
@MappedSuperclass
public abstract class BaseEntity { ... }

@Entity public class Order   extends BaseEntity { ... }
@Entity public class Product extends BaseEntity { ... }

// ✗ Cannot query all BaseEntity instances:
// em.createQuery("SELECT b FROM BaseEntity b") → Exception!
// ✓ Query each entity type separately:
// em.createQuery("SELECT o FROM Order o")
// em.createQuery("SELECT p FROM Product p")

// @Inheritance(SINGLE_TABLE) — polymorphic query IS possible
@Entity
@Inheritance(strategy = InheritanceType.SINGLE_TABLE)
@DiscriminatorColumn(name = "dtype")
public abstract class Payment { ... }   // has its OWN table

@Entity @DiscriminatorValue("CARD")
public class CardPayment extends Payment { ... }

@Entity @DiscriminatorValue("BANK")
public class BankTransfer extends Payment { ... }

// ✓ Polymorphic query works:
// em.createQuery("SELECT p FROM Payment p WHERE p.amount > 100")

Key Points to Remember

  • 1@MappedSuperclass contributes fields to subclass entity tables — no table of its own.
  • 2Ideal for sharing id, createdAt, updatedAt, createdBy across all entities.
  • 3Combine with @EntityListeners(AuditingEntityListener.class) for auto audit population.
  • 4@EnableJpaAuditing + AuditorAware<T> bean enables createdBy/updatedBy auto-fill.
  • 5@MappedSuperclass does NOT support polymorphic queries — use @Inheritance for that.
  • 6Multiple levels of @MappedSuperclass are supported (base → intermediate → entity).

Interview Questions

Sign in to ask Aria
1

What is @MappedSuperclass and does it create a DB table?

EasyTCS
2

What is the difference between @MappedSuperclass and @Inheritance?

MediumAmazon
3

How do you automatically populate createdAt and updatedAt in a Spring Data JPA entity?

MediumInfosys
4

Can you query all instances of a @MappedSuperclass type with JPQL?

MediumPivotal
5

How does AuditorAware integrate with Spring Security to track who modified an entity?

HardNetflix

Ask Aria about @MappedSuperclass

Your personal AI tutor — ask anything about this concept

Revision Status

Personal Notes

Sign in to save personal notes for this topic.

Discussion

Sign in to join the discussion.

Loading discussion…