The Hibernate error “Unable to locate persister” means that we passed a class to Hibernate that is not a mapped entity in the current persistence unit. A persister is the object Hibernate builds at startup for each entity, and it knows the table, the columns, the id and the SQL. When em.persist() or em.find() gets a class with no persister, the call fails.
We meet the error when we add a new entity class and forget to register it, or right after an upgrade from Hibernate 5 to Hibernate 6 or 7.
The following example saves a FerryRoute object that Hibernate does not know as an entity. Hibernate 5 and 6 print “Unable to locate persister”, whereas Hibernate 7 reports the same problem as “Unknown entity type”.
java.lang.IllegalArgumentException: Unable to locate persister: com.howtodoinjava.hibernate.persister.FerryRoute
at org.hibernate.internal.SessionImpl.firePersist(SessionImpl.java:764)
at org.hibernate.internal.SessionImpl.persist(SessionImpl.java:745)
Caused by: org.hibernate.UnknownEntityTypeException: Unable to locate persister: com.howtodoinjava.hibernate.persister.FerryRoute
java.lang.IllegalArgumentException: Unknown entity type 'com.howtodoinjava.hibernate.persister.FerryRoute' ('FerryRoute' does not belong to this persistence unit)
Caused by: org.hibernate.UnknownEntityTypeException: Unknown entity type 'com.howtodoinjava.hibernate.persister.FerryRoute'
Notice that both versions throw an IllegalArgumentException that wraps org.hibernate.UnknownEntityTypeException, so the cause and the fix are the same.
Next, we go through the five causes of the error, from a class that is not registered to a Spring Boot app that does not scan the entity package, and fix each one.
1. Why Hibernate Cannot Find the Entity Persister
Hibernate builds its persisters once, when the EntityManagerFactory starts. It takes the classes we registered, keeps those annotated with jakarta.persistence.Entity and creates one persister per entity. Later, every persist() or find() looks up the persister by the name of the class it receives. The error comes from one of three places in that flow.

The wording changed between versions, but the cause did not. Hibernate 5.6 and 6.6 even print different messages for persist() and find().
| Hibernate | em.persist(route) | em.find(FerryRoute.class, 1L) |
|---|---|---|
| 5.6 | Unknown entity: …FerryRoute | Unable to locate persister: …FerryRoute |
| 6.6 | Unable to locate persister: …FerryRoute | Unable to locate entity descriptor: …FerryRoute |
| 7.0 | Unknown entity type: …FerryRoute | Unknown entity type: …FerryRoute |
| 7.4 | Unknown entity type ‘…FerryRoute’ plus the reason in brackets | Unknown entity type ‘…FerryRoute’ |
The reason in Hibernate 7.4 tells us which cause we hit, either ‘FerryRoute’ does not belong to this persistence unit or ‘FerryRoute’ is not annotated ‘@Entity’.
Our example is a ferry timetable with one entity, FerryRoute (fromPort, toPort, durationMinutes), on Hibernate 7.4 and H2.
1.1. The Entity Is Not Registered
With HibernatePersistenceConfiguration, Hibernate knows only the classes we pass to managedClass() or managedClasses(). If we forget one, the factory still starts without errors, and the first call fails. For example, a team adds FerryRoute to a ferry booking app and writes the booking code, but nobody adds the class to the configuration, so the first booking request throws the exception.
EntityManagerFactory emf = new HibernatePersistenceConfiguration("ferry")
.managedClasses() // FerryRoute not listed
.jdbcUrl("jdbc:h2:mem:ferry;DB_CLOSE_DELAY=-1")
.createEntityManagerFactory();
emf.runInTransaction(em -> em.persist(new FerryRoute("Helsinki", "Tallinn", 120)));
// IllegalArgumentException: Unknown entity type '...FerryRoute' ('FerryRoute' does not belong to this persistence unit)
A persistence.xml unit fails the same way when the class is not in a <class> element and unlisted classes are excluded.
<persistence-unit name="ferry-unlisted">
<exclude-unlisted-classes>true</exclude-unlisted-classes>
...
</persistence-unit>
1.2. The Class Has No @Entity
A class with @Id fields but without @Entity is not an entity. Hibernate ignores a class without @Entity and logs no warning, even when we register it, so the error shows up only at the first call.
public class FerryRoute { // @Entity is missing
@Id @GeneratedValue
private Long id;
private String fromPort;
...
}
int entityCount = emf.getMetamodel().getEntities().size(); // 0
em.persist(new FerryRoute("Helsinki", "Tallinn", 120));
// IllegalArgumentException: Unknown entity type '...FerryRoute' ('FerryRoute' is not annotated '@Entity')
1.3. The Entity Uses javax.persistence Instead of jakarta.persistence
The old javax import shows up right after an upgrade, with no change in our own code, because Hibernate 6 moved from Java Persistence (javax.persistence) to Jakarta Persistence (jakarta.persistence). An entity copied from a Hibernate 5 or Spring Boot 2 project still compiles when an old javax.persistence-api jar is on the classpath, for example through a library. Hibernate 6 and 7 do not read those annotations, so they treat the class as a plain class.
import javax.persistence.Entity; // Hibernate 5 and earlier
import javax.persistence.Id;
@Entity
public class FerryRoute { ... }
em.persist(new FerryRoute("Helsinki", "Tallinn", 120));
// Hibernate 6.6: Unable to locate persister: com.howtodoinjava.hibernate.persister.FerryRoute
// Hibernate 7.4: Unknown entity type '...FerryRoute' ('FerryRoute' is not annotated '@Entity')
1.4. A DTO or Proxy Class Is Passed Instead of the Entity
Hibernate looks up the persister by the exact class we pass. A DTO (a plain class or record that only carries data) has the same fields as the entity but no persister.
public record FerryRouteDto(String fromPort, String toPort, int durationMinutes) { }
em.persist(new FerryRouteDto("Turku", "Stockholm", 660));
// Unknown entity type '...dto.FerryRouteDto' ('FerryRouteDto' is not annotated '@Entity')
FerryRouteDto found = em.find(FerryRouteDto.class, 1L);
// IllegalArgumentException: Unknown entity type '...dto.FerryRouteDto'
The same happens with a proxy. Both em.getReference() and lazy associations return a subclass generated at runtime, so generic code that calls getClass() gets the proxy class. For example, a generic audit helper that reloads any entity with em.find(entity.getClass(), id) fails as soon as it gets a proxy.
FerryRoute ref = em.getReference(FerryRoute.class, id);
String className = ref.getClass().getName(); // ...FerryRoute$HibernateProxy
FerryRoute found = em.find(ref.getClass(), id);
// IllegalArgumentException: Unknown entity type '...FerryRoute$HibernateProxy'
1.5. Spring Boot Does Not Scan the Entity Package
Spring Boot looks for entities only in the package of the @SpringBootApplication class and its sub-packages. An entity in a parent or sibling package is never registered. For example, a team moves the application class into a boot sub-package during a refactoring, and the entities in the parent package drop out of the scan.

With an EntityManager, the error appears at the first call, with the same message as in section 1.1. With a Spring Data repository for that entity, the application does not start.
BeanCreationException: Error creating bean with name 'ferryRouteRepository' ...: Not a managed type: class com.howtodoinjava.hibernate.persister.FerryRoute
2. How to Fix It
Every cause has a short fix. The order follows section 1, so we can jump to the cause that the reason in brackets names.
2.1. Register the Entity
We add the class to the configuration, either in code with managedClasses() or as a <class> element in persistence.xml. A missing class is the usual problem after we add a new entity to a project that lists its classes.
.managedClasses() // before
.managedClasses(FerryRoute.class) // after: insert into FerryRoute (...) values (?,?,?,?)
<persistence-unit name="ferry-listed">
<class>com.howtodoinjava.hibernate.persister.FerryRoute</class>
<exclude-unlisted-classes>true</exclude-unlisted-classes>
...
</persistence-unit>
2.2. Add @Entity From jakarta.persistence
The fix for sections 1.2 and 1.3 is the same, so we annotate the class with jakarta.persistence.Entity. The import decides which annotation the class gets, so we search the project for javax.persistence and replace every one.
import jakarta.persistence.Entity;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.Id;
@Entity
public class FerryRoute { ... }
String entityName = emf.getMetamodel().entity(FerryRoute.class).getName(); // "FerryRoute"
If javax.persistence-api still shows up in mvn dependency:tree, we exclude it, so the old import no longer compiles.
2.3. Pass the Entity Class, Not a DTO or Proxy
We map the DTO to an entity before saving, and read DTOs with a query instead of find().
FerryRoute route = new FerryRoute(dto.fromPort(), dto.toPort(), dto.durationMinutes());
em.persist(route); // insert into FerryRoute (...) values (?,?,?,?)
FerryRouteDto loaded = em.createQuery(
"select r.fromPort, r.toPort, r.durationMinutes from FerryRoute r where r.id = :id",
FerryRouteDto.class)
.setParameter("id", id)
.getSingleResult(); // FerryRouteDto[fromPort=Turku, toPort=Stockholm, durationMinutes=660]
For a proxy, Hibernate.getClass() returns the real entity class. It initializes the proxy first, so it runs a SELECT when the proxy is not loaded yet.
Class<?> type = Hibernate.getClass(ref); // ...FerryRoute (select ... from FerryRoute fr1_0 where fr1_0.id=?)
Object route = em.find(type, id); // Turku -> Stockholm (660 min)
2.4. Point Spring Boot to the Entity Package
We add @EntityScan to the application class, or move the application class to a package above all entities. In Spring Boot 4 the annotation is in org.springframework.boot.persistence.autoconfigure; Spring Boot 3 has it in org.springframework.boot.autoconfigure.domain.
import org.springframework.boot.persistence.autoconfigure.EntityScan;
@SpringBootApplication
@EntityScan(basePackageClasses = FerryRoute.class)
public class FixedFerryApp { }
repository.save(new FerryRoute("Helsinki", "Tallinn", 120));
long count = repository.count(); // 1
The complete project on GitHub covers each cause and each fix with JUnit tests (20 in total), including Spring Boot 4.1.1 and the old javax annotations (mvn -q compile exec:java, mvn test).
3. Unknown Entity Error FAQs
3.1. Why Do persist(), find() and Queries Show Different Messages?
Each API checks the class in its own place, so one missing entity produces several messages, from persist() and find() to an HQL query and the Criteria API. All of them mean “this class is not an entity in this persistence unit”.
| Call (Hibernate 7.4) | Message |
|---|---|
| em.persist(route) | Unknown entity type ‘…FerryRoute’ (‘FerryRoute’ does not belong to this persistence unit) |
| em.find(FerryRoute.class, 1L) | Unknown entity type ‘…FerryRoute’ |
| em.createQuery(“from FerryRoute”) | UnknownEntityException: Could not resolve root entity ‘FerryRoute’ |
| cb.createQuery(…).from(FerryRoute.class) | Not an entity: …FerryRoute |
| Spring Data repository | Not a managed type: class …FerryRoute |
The JPA specification requires the IllegalArgumentException, because EntityManager.persist() throws it “if the instance is not an entity”.
3.2. Why Did My persistence.xml Stop Finding Entities in Hibernate 7?
Hibernate 7 moved classpath scanning out of hibernate-core into the hibernate-scan-jandex module. A unit without <class> elements that relied on scanning finds no entities after the upgrade.
int entityCount = emf.getMetamodel().getEntities().size(); // 0
em.persist(new FerryRoute("Helsinki", "Tallinn", 120));
// Unknown entity type '...FerryRoute' ('FerryRoute' does not belong to this persistence unit)
Adding hibernate-scan-jandex to the dependencies brings scanning back.
<dependency>
<groupId>org.hibernate.orm</groupId>
<artifactId>hibernate-scan-jandex</artifactId>
<version>7.4.11.Final</version>
</dependency>
Hibernate scans the root of the persistence unit, which is the jar or directory that holds META-INF/persistence.xml. The Jakarta Persistence specification calls scanning optional in Java SE, so listing each class is the portable choice.
3.3. Is “Unknown entity” in Hibernate 5 the Same Error?
Yes. Hibernate 5.6 reports an unmapped class as Unknown entity from persist() and as org.hibernate.MappingException: Unknown entity: … from the old Session.save(). Old answers that fix “Unknown entity” (register the class, add @Entity) apply here too, as long as we use jakarta imports on Hibernate 6 and 7. Session.save() no longer exists in Hibernate 7; persist() replaces it.
4. Conclusion
“Unable to locate persister” and “Unknown entity type” both say that Hibernate has no entity mapping for the class it received. To fix it, we check that the class is registered or scanned and carries jakarta.persistence.Entity. We also check that the code passes the entity class itself, not a DTO or a proxy. In Hibernate 7.4, the text in brackets at the end of the message points to the right cause.
5. References
- EntityManager JavaDoc (Jakarta Persistence 3.2)
- Jakarta Persistence 3.2 specification: mapping-file, jar-file, class, exclude-unlisted-classes
- Hibernate ORM 7.0 Migration Guide: Entity Discovery
- UnknownEntityTypeException JavaDoc (Hibernate 7.4)
- Spring Boot Reference: Entity Classes
- EntityScan JavaDoc (Spring Boot 4)
Happy Learning !!
Thanks for the helpful solution!
you are a genius
Glad, it helped.
Thanks a lot.
Wow, nice it work for me
Thanks a lot for this explanation! It was very helpfull for me!