Table-per-class mapping gives each concrete entity class its own table. A subclass table holds both its own persistent properties and those inherited from its superclass. This represents a Java inheritance hierarchy without introducing inheritance relationships between SQL tables; shared columns are duplicated. section 7.0 section 7.2
For example, an abstract BillingDetails entity can have CreditCard and BankAccount subclasses stored in CREDITCARD and BANKACCOUNT. Declare @Inheritance(strategy = InheritanceType.TABLE_PER_CLASS) on BillingDetails and @Entity on each subclass. Put the identifier mapping on the superclass so every subclass table inherits it and has an ID primary key. If BillingDetails were concrete, it would also need a table. section 7.2
Listing 7.8 Mapping BillingDetails with TABLE_PER_CLASS
Path: Ch07/mapping-inheritance-tableperclass/src/main/java/com/manning /javapersistence/ch07/model/BillingDetails.java @Entity @Inheritance(strategy = InheritanceType.TABLE_PER_CLASS) public abstract class BillingDetails { @Id @GeneratedValue(generator = “ID_GENERATOR”) private Long id; @NotNull private String owner; // . . . }
The superclass declaration places the inheritance strategy, generated identifier, and shared owner property in one mapping. section 7.2
The explicit TABLE_PER_CLASS strategy preserves polymorphic queries. A repository query for all BillingDetails, or the JPQL query `select bd from BillingDetails bd`, reads across concrete tables. The generated SQL combines their rows with UNION ALL, fills columns absent from a particular subtype with null, and includes a literal identifying each concrete class. A superclass-targeting repository can participate once BillingDetails is an entity and its repository is no longer marked @NoRepositoryBean. section 7.2
select
ID, OWNER, EXPMONTH, EXPYEAR, CARDNUMBER,
ACCOUNT, BANKNAME, SWIFT, CLAZZ_
from
( select
ID, OWNER, EXPMONTH, EXPYEAR, CARDNUMBER,
null as ACCOUNT,
null as BANKNAME,
null as SWIFT,
1 as CLAZZ_
from
CREDITCARD
union all
select
id, OWNER,
null as EXPMONTH,
null as EXPYEAR,
null as CARDNUMBER,
ACCOUNT, BANKNAME, SWIFT,
2 as CLAZZ_
from
BANKACCOUNT
) as BILLINGDETAILS
The generated query shows how separate subtype tables supply one polymorphic result, including null placeholders and class-identifying literals. section 7.2
Choose the variant and its tradeoffs deliberately:
- Implicit table-per-concrete-class mapping is simplest when superclass queries and associations are unnecessary, but it supports polymorphic associations poorly. Duplicating columns with the same meaning also complicates schema evolution. section 7.7 section 7.9
- Prefer explicit TABLE_PER_CLASS when polymorphic queries or associations may be needed later. JPA support for this strategy is optional, so check the implementation. section 7.7 section 7.2
- For frequent polymorphic access, compare SINGLE_TABLE and JOINED against TABLE_PER_CLASS. Subtype attributes, nullable-column requirements, and the cost of joins versus unions affect the choice; complex cases may warrant SQL execution plans with real data. section 7.7
A polymorphic one-to-many collection can also target the superclass: Hibernate uses the appropriate SQL, including unions for TABLE_PER_CLASS, when loading its elements. The target superclass must be mapped as @Entity with @Inheritance, not merely as @MappedSuperclass. section 7.8.2
