Mapping an inheritance hierarchy
Pick between one shared table, a table per class and a joined hierarchy with eyes open.
Open this lesson in the learning hubKey points
SINGLE_TABLEis the default: every subclass shares one table plus a discriminator column. No joins, fastest to read.- The price is that every column a subclass adds must be nullable, so the database can no longer enforce a required field.
JOINEDgives each class its own table and keeps the constraints, at the cost of a join per level on every read.TABLE_PER_CLASScopies the parent columns into each subclass table. A query on the parent becomes aUNION ALL.@MappedSuperclassis not inheritance mapping - it only shares fields, and you cannot query or reference it polymorphically.- If the subclasses share almost nothing, use separate entities. Inheritance in your domain model does not have to reach the schema.
Example
@Entity
@Inheritance(strategy = InheritanceType.SINGLE_TABLE)
@DiscriminatorColumn(name = "payment_type") // payment_type = CARD | BANK
public abstract class Payment {
@Id @GeneratedValue private Long id;
private long amountCents;
}
@Entity
@DiscriminatorValue("CARD")
public class CardPayment extends Payment {
private String last4; // must be nullable: BANK rows have no last4
}
@Entity
@DiscriminatorValue("BANK")
public class BankPayment extends Payment {
private String iban; // nullable for the same reason
}
// select p from Payment p
// SINGLE_TABLE -> select * from payment
// JOINED -> payment left join card_payment left join bank_payment
// TABLE_PER_CLASS -> select ... from card_payment union all select ... from bank_payment
SINGLE_TABLE unless you need the not-null constraints back.
This is a reading copy. The full lesson — with the visual explainer, the interactive lab and a Run button for the code — lives in the Hibernate course, and every lesson in it is listed on the Hibernate contents page.