Hibernate Inheritance Strategies

Gaurav Talele
4 min readMay 29, 2021

There are three inheritance mapping strategies in hibernate:

  1. Single Table Per Class: Only one table is created for all the classes involved in hierarchy. Here we maintain an extra discriminator field in table to differentiate between the tables.
  2. Table Per Subclass: One table for each class is created. The above hierarchy gets three tables. Here, foreign key is maintained between the tables.
  3. Table Per Concrete Class: One table for each concrete class (subclass) is created but not of super class. The above hierarchy gets two tables. As a special case, the super class can be an abstract or interface. Here, foreign key is not maintained.

The relational model supported by Hibernate is “has-a” relationship. How Hibernate writes tables for the Java classes involved in inheritance? Yes, That's what we are reveling in this article.

Single Table Per Class:

In Single table per subclass, the union of all the properties from the inheritance hierarchy is mapped to one table. As all the data goes in one table, a discriminator is used to differentiate between different type of data.

User (Base class)// DiscriminatorColumn - Tells about the type of data
// DiscriminatorValue - Is the data is representing User type, the // value is "USER"
@Entity
@Inheritance(strategy=InheritanceType.SINGLE_TABLE)
@DiscriminatorColumn(name="DISCRIMINATOR", discriminatorType=DiscriminatorType.STRING)
@DiscriminatorValue("USER")
@Table(name="BASIC_USER")
public class User {
protected long id;
protected String name;
...
}
-------------------------------------------------------------Customer Class (Derived from User)
//There is no id column@Entity
@DiscriminatorValue("CUST")
public class Customer extends User{
protected double creditLimit;
...
}
--------------------------------------------------------------
Employee Class (Derived From User)
//There is no id column@Entity
@DiscriminatorValue("EMP")
public class Employee extends User{
protected String rank
...
}

Advantages of Single Table per class hierarchy:

  • Simplest to implement.
  • Only one table to deal with.
  • Performance wise better than all strategies because no joins or sub-selects need to be performed.

Disadvantages:

  • Most of the column of table are nullable so the NOT NULL constraint cannot be applied.
  • Tables are not normalized.

Table Per Sub Class:

In this case all the classes are mapped to its own table. It’s highly normalized but performance is not good.

User class
----------
@Entity
@Inheritance(strategy=InheritanceType.JOINED)
@Table(name="BASIC_USER")
public class User implements Serializable{
protected long id;
protected String name;
...
}
-------------------------------------------------------------
Employee class@Entity
@PrimaryKeyJoinColumn(name="EMPLOYEE_ID")
public class Employee extends User{
protected String rank;
...
}

The derived class mapped table contain the foreign key which maps it to the base class. The table structure is as follows.

Basic_User => ID, NAME

Employee => EMPLOYEE_ID (Acts both as primary key and foreign key.), RANK

Advantage:

  • Tables are normalized.
  • Able to define NOT NULL constraint.

Disadvantage:

  • Does not perform as well as SINGLE_TABLE strategy

Table Per Concrete Class:

In this case let’s say our User class is abstract and Customer and Employee are concrete classes. So the table structure that comes out is basically one table for Customer and one table for Employee. The data for User is duplicated in both the tables.

User Class@Entity
@Inheritance(strategy=InheritanceType.TABLE_PER_CLASS)
public abstract class User{
protected long id;
protected String name;
...
}
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
public long getId() {
}
-----------------------------------------------------------
Customer class
@Entity
public class Customer extends User{
protected double creditLimit;
...
}

Advantage:

  • Possible to define NOT NULL constraints on the table.

Disadvantage:

  • Tables are not normalized.
  • To support polymorphism either container has to do multiple trips to database or use SQL UNION kind of feature.

Now it is very obvious question that, Which Strategy to Choose ???

Usually the choice is between Single Table and Table per subclass strategy. Table per concrete class is optional in JPA and may hinder your portability later on. They also represent the two ends of the spectrum. Some rule of thumbs are:

  1. If there are many properties common in the base class and very less uncommon properties in derived class. Go for Single table strategy. However make sure your database architect is comfortable with nullable constraint not put on the properties of derived class. If there are too many uncommon properties, you might want to go for table per subclass strategy.
  2. Another criteria is the amount of polymorphic queries you do. If most of the time you fetch Customer and Employees separately you can go for Table per subclass as this will involve join only on two tables a time. However if you have requirements where you fetch User polymorphically most of the time, Single table strategy will give better performance.

Another Question Might arise how to Inherit From a non entity base class ???

Let’s say we want to put Audit information in many tables. We can make Audit as a base class and make our entities class to inherit from Audit class.

Audit class@MappedSuperclass
public class Audit {
protected Date updateDate;
protected Date createDate;
@Temporal(TemporalType.TIMESTAMP)
public Date getCreateDate() {
return createDate;
}

...
}
User class
// If we want to overried the column name than
// AttributeOverride is required
@Entity
@Table(name="BASIC_USER")
@AttributeOverride(name="createDate",column=@Column(name="CREATE_DATE"))
public class User extends Audit{
...
}

--

--

Gaurav Talele

An ambitious Full Stack evangelist in Angular, Typescript, Spring Boot Node JS, C#, Dot Net Core WEB API, MS SQL, Redis, MongoDB, RabbitMQ, Docker and AWS.