LearnAI ToolsCareerPractice BuildsPlayContact
Lesson 920 min read

Mapping Annotations

Learn the core Hibernate mapping annotations — @Entity, @Table, @Column, and @Id — and exactly what each one controls.

Introduction

The previous lesson used a bare-bones entity with mostly default behavior. In practice, you will frequently want more control — a different table name, a different column name, length constraints, or nullability rules. This lesson covers the four annotations that give you that control: @Entity, @Table, @Column, and @Id.

What You Will Learn
  • What @Entity actually configures, beyond just marking a class.
  • How @Table overrides the default table name and adds constraints.
  • How @Column controls column name, length, nullability, and uniqueness.
  • What @Id requires and how it is typically paired with other annotations.

@Entity

@Entity marks a class as a JPA-managed entity. By default, Hibernate uses the class's simple name as the table name — but @Entity also accepts an optional name attribute, used to reference the entity in queries (this is different from the table name, which @Table controls).

@Entity(name = "StudentEntity")
public class Student {
// ...
}
Note

The name attribute on @Entity affects how the entity is referred to in JPQL/HQL queries (e.g., "FROM StudentEntity"), not the actual database table name — that is a common point of confusion.

@Table

@Table lets you explicitly set the database table name — useful when it should differ from the class name, such as following a plural naming convention. It also supports schema, catalog, and unique constraints.

import jakarta.persistence.Entity;
import jakarta.persistence.Table;
import jakarta.persistence.UniqueConstraint;
@Entity
@Table(name = "students", uniqueConstraints = {
@UniqueConstraint(columnNames = "email")
})
public class Student {
// ...
}
Effect on generated schema

Click Run to see what this code prints.

Without @Table, Hibernate would have used "Student" as the table name instead of "students."

@Column

@Column gives you control over an individual field's column: its name, whether it can be null, its maximum length, and whether it must be unique.

import jakarta.persistence.Column;
@Column(name = "full_name", nullable = false, length = 100)
private String name;
@Column(unique = true, nullable = false)
private String email;
AttributePurpose
nameOverrides the column name (defaults to the field name).
nullableWhether the column allows NULL values (defaults to true).
lengthMaximum length for String columns (defaults to 255).
uniqueAdds a unique constraint on the column.
Effect on generated schema

Click Run to see what this code prints.

@Id

@Id marks exactly one field as the entity's primary key. Every entity must have one, and Hibernate uses it to uniquely identify each row and to detect whether an entity is new or already persisted.

import jakarta.persistence.Id;
@Id
private Long id;

On its own, @Id means the value must be assigned manually before saving, as in the previous lesson. Pairing it with @GeneratedValue lets the database or Hibernate generate the value automatically — covered in full in the next lesson.

A Fully Annotated Example

Putting all four annotations together produces a clear, explicit mapping.

Student.java
import jakarta.persistence.*;
@Entity
@Table(name = "students")
public class Student {
@Id
private Long id;
@Column(name = "full_name", nullable = false, length = 100)
private String name;
@Column(unique = true, nullable = false)
private String email;
public Student() {
}
// getters and setters omitted for brevity
}
Generated CREATE TABLE statement

Click Run to see what this code prints.

Common Mistakes

Avoid These Mistakes
  • Confusing @Entity(name = ...) with @Table(name = ...) — they control different things (query name vs. table name).
  • Assuming @Column is required on every field — it is optional and only needed when overriding defaults.
  • Forgetting nullable = false on fields that should be mandatory, allowing invalid NULL data through.
  • Placing @Id on a field type that cannot uniquely and reliably identify a row.

Best Practices

  • Be explicit with @Table and @Column when the defaults do not match your team's naming conventions.
  • Set nullable = false on any field that represents required data, matching your business rules.
  • Use unique = true for fields like email that must not repeat, rather than enforcing it only in application code.
  • Keep column length limits realistic and intentional rather than always relying on the 255-character default.

Frequently Asked Questions

No. If omitted, Hibernate simply uses the entity's class name as the table name.

No. Fields without @Column still get mapped, using the field name as the column name and sensible defaults.

Not directly with a single @Id each — composite primary keys use different annotations (@EmbeddedId or @IdClass), which are outside the scope of this lesson.

Common choices are Long, Integer, String, or UUID — any type that can reliably and uniquely identify a row.

Key Takeaways

  • @Entity marks a class as JPA-managed; its name attribute affects queries, not the table name.
  • @Table controls the actual database table name and table-level constraints.
  • @Column controls a field's column name, nullability, length, and uniqueness.
  • @Id marks the primary key field and is required on every entity.

Summary

With @Entity, @Table, @Column, and @Id, you now have precise control over how your Java classes map to database tables. Next, you will focus specifically on primary keys — how @GeneratedValue works, and the differences between IDENTITY, SEQUENCE, and AUTO generation strategies.

Next Lesson →

Primary Keys & @GeneratedValue