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 | price2
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