Hibernate Tip: Difference between @JoinColumn and @PrimaryKeyJoinColumn

Take your skills to the next level!

The Persistence Hub is the place to be for every Java developer. It gives you access to all my premium video courses, monthly Java Persistence News, monthly coding problems, and regular expert sessions.

Hibernate Tips is a series of posts in which I describe a quick and easy solution for common Hibernate questions. If you have a question for a future Hibernate Tip, please post a comment below.


Himanshu Srivastava asked today’s question on my YouTube channel:

“What’s the difference between@JoinColumn and @PrimaryKeyJoinColumn?
Also, should we use @PrimaryKeyJoinColumn or @JoinColumn?”


The @JoinColumn and the @PrimaryKeyJoinColumn might seem very similar, but they are used in 2 different contexts. You can use the @JoinColumn annotation to map the foreign key column of a managed association. The @PrimaryKeyJoinColumn specifies the mapping of the foreign key column of a secondary table or the foreign key column in an inheritance mapping that uses the JOINED strategy.

So, the annotation you need to use depends on the context in which you want to customize the mapping of the foreign key column. Let’s take a look at an example mapping for both annotations.

Using the @JoinColumn annotation

When you add the @JoinColumn annotation to your association mapping, you can define the name of the foreign key column that represents your association in the table model.

I use it in the following code snippet to tell Hibernate it shall use the column book_key as the foreign key column of the many-to-one association.

public class Review {

	@GeneratedValue(strategy = GenerationType.AUTO)
	@Column(name = "id", updatable = false, nullable = false)
	private Long id;

	private String comment;

	@ManyToOne(fetch = FetchType.LAZY)
	@JoinColumn(name = "book_key")
	private Book book;


When you activate the logging of SQL statements and fetch a Review entity from the database, you can see that Hibernate uses the book_key column to map the association.

12:48:50,686 DEBUG [org.hibernate.SQL] - 
        reviews0_.book_key as book_key3_2_0_,
        reviews0_.id as id1_2_0_,
        reviews0_.id as id1_2_1_,
        reviews0_.book_key as book_key3_2_1_,
        reviews0_.comment as comment2_2_1_ 
        Review reviews0_ 

Using the @PrimaryKeyJoinColumn annotation

When you use the inheritance mapping strategy JOINED, all columns mapped by the superclass get mapped to one database table, and the specific attributes of a subclass get mapped to a different table. Hibernate has to join these 2 tables, whenever you use the subclass. The primary key columns of each table are then used as the join columns.

You can see the superclass of such an inheritance hierarchy in the following code snippet.

@Inheritance(strategy = InheritanceType.JOINED)
public class Publication {

	@GeneratedValue(strategy = GenerationType.AUTO)
	private Long id;

	private int version;


By default, Hibernate expects that the primary key columns of both tables have the same name. If that’s not the case, you can annotate your subclass with a @PrimaryKeyJoinColumn.

@PrimaryKeyJoinColumn(name = "book_id")
public class Book extends Publication {

	private String title;
	@OneToMany(mappedBy = "book", cascade = CascadeType.REMOVE)
	private List<Review> reviews = new ArrayList<Review>();


As you can see in the log message, Hibernate maps the primary key of the book table to the book_id column.

12:48:50,681 DEBUG [org.hibernate.SQL] - 
        book0_.book_id as id1_1_0_,
        book0_1_.version as version2_1_0_,
        book0_.title as title1_0_0_ 
        Book book0_ 
    inner join
        Publication book0_1_ 
            on book0_.book_id=book0_1_.id 

Learn more:

If you want to learn more about foreign key mappings, you should read the following articles:

Hibernate Tips Book

Get more recipes like this one in my new book Hibernate Tips: More than 70 solutions to common Hibernate problems.

It gives you more than 70 ready-to-use recipes for topics like basic and advanced mappings, logging, Java 8 support, caching, and statically and dynamically defined queries.

Get it now!

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.