Cheat SheetsHibernate & JPAInheritance

Inheritance — Cheat Sheet

Hibernate & JPA · 4 topics. Download the PDF or the Instagram carousel and share it.

Cheat Sheet · AiCanCode.org
Inheritance
Hibernate & JPA4 topicsQuick revision reference
1

@MappedSuperclass

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

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

Inheritance — Single Table Strategy

All subclass data is stored in one table with a DTYPE discriminator column; best performance (no joins) but wastes space with many nullable columns for sparse hierarchies.

  • SINGLE_TABLE stores all subclasses in one table with a discriminator column (default: DTYPE)
  • No joins required — fastest query performance of all three inheritance strategies
  • Subclass-specific columns cannot be NOT NULL at the DB level (nullable for other types)
  • @DiscriminatorColumn customises the discriminator column name and type
  • @DiscriminatorValue on each subclass sets its discriminator string
  • Best for shallow hierarchies with few subclass fields; avoid for large sparse schemas
Java — SINGLE_TABLE inheritance with discriminator
@Entity
@Inheritance(strategy = InheritanceType.SINGLE_TABLE)
@DiscriminatorColumn(name = "payment_type", discriminatorType = DiscriminatorType.STRING)
@Table(name = "payments")
public abstract class Payment {
    @Id @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    @Column(nullable = false, precision = 10, scale = 2)
    private BigDecimal amount;

    private LocalDateTime createdAt;
}

@Entity
@DiscriminatorValue("CARD")
public class CardPayment extends Payment {
    private String cardLastFour;    // nullable at DB level — not present for other types
    private String cardBrand;
}

@Entity
@DiscriminatorValue("BANK")
public class BankPayment extends Payment {
    private String accountNumber;
    private String sortCode;
}
3

Inheritance — Table per Class Strategy

Each concrete subclass gets its own table with all inherited columns repeated; polymorphic queries use UNION which can be expensive; rarely recommended.

  • Each concrete subclass gets its own table; abstract base class has no table
  • Inherited columns are duplicated in every subclass table — no base table to join
  • Polymorphic queries on the base class generate UNION ALL — expensive with many subclasses
  • IDENTITY strategy is incompatible — use SEQUENCE or TABLE for unique IDs across tables
  • Single-subclass queries are fast (no join, no union); only polymorphic queries are costly
  • Rarely recommended — prefer JOINED for normalisation or SINGLE_TABLE for polymorphic perf
Java — TABLE_PER_CLASS inheritance
@Entity
@Inheritance(strategy = InheritanceType.TABLE_PER_CLASS)
public abstract class Notification {
    @Id
    @GeneratedValue(strategy = GenerationType.SEQUENCE)  // IDENTITY not allowed — must be SEQUENCE or TABLE
    private Long id;

    @Column(nullable = false)
    private String recipient;

    private LocalDateTime sentAt;
}

@Entity
@Table(name = "email_notifications")  // contains: id, recipient, sent_at, subject, body
public class EmailNotification extends Notification {
    private String subject;
    private String body;
}

@Entity
@Table(name = "sms_notifications")    // contains: id, recipient, sent_at, phone_number, message
public class SmsNotification extends Notification {
    private String phoneNumber;
    private String message;
}
4

Inheritance — Joined Strategy

Base class gets its own table; subclass tables hold only their columns, joined by PK; good normalisation but requires a JOIN per subclass level on every query.

  • JOINED: base class has its own table; each subclass table holds only its additional columns
  • Subclass tables share PK with base table — the subclass PK is a FK to the base table
  • Polymorphic queries use LEFT OUTER JOIN across all subclass tables — one JOIN per level
  • Best normalisation: subclass columns can have NOT NULL; no wasted columns
  • @PrimaryKeyJoinColumn customises the FK column name in the subclass table
  • Keep hierarchies shallow — every level adds a JOIN; 2-3 levels is a practical limit
Java — JOINED inheritance strategy
@Entity
@Inheritance(strategy = InheritanceType.JOINED)
@DiscriminatorColumn(name = "vehicle_type")
@Table(name = "vehicles")
public abstract class Vehicle {
    @Id @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;                      // table: vehicles(id, make, model, vehicle_type)
    private String make;
    private String model;
}

@Entity
@DiscriminatorValue("CAR")
@Table(name = "cars")
public class Car extends Vehicle {
    private int doors;                    // table: cars(id FK→vehicles.id, doors)
    private String bodyStyle;
}

@Entity
@DiscriminatorValue("TRUCK")
@Table(name = "trucks")
public class Truck extends Vehicle {
    private double payloadTons;           // table: trucks(id FK→vehicles.id, payload_tons)
}
Learn this free with Aria, your AI tutor → AiCanCode.org/learn/hibernate