hibernate/hibernate-orm · error · EntityTypeException

Could not resolve entity class '{}'

Error message

Could not resolve entity class '{}'

What it means

JpaMetamodelImpl throws EntityTypeException('Could not resolve entity class') when asked for an EntityDomainType for a Java class that is neither itself a registered entity nor has any registered entity subclass (createPolymorphicRootDescriptor finds zero matching descriptors). This is the JPA metamodel/SQM entry point — entity(Class), criteria roots, and graph creation all funnel through it.

Source

Thrown at hibernate-core/src/main/java/org/hibernate/metamodel/model/domain/internal/JpaMetamodelImpl.java:572

		if ( proxyEntityName != null ) {
			return entity( proxyEntityName );
		}

		// otherwise, try to handle it as a polymorphic reference
		final var polymorphicDomainType =
						polymorphicEntityReferenceMap.get( javaType );
		if ( polymorphicDomainType != null ) {
			return polymorphicDomainType;
		}
		else {
			final var polymorphicRootDescriptor =
					createPolymorphicRootDescriptor( javaType );
			if ( polymorphicRootDescriptor != null ) {
				return polymorphicRootDescriptor;
			}
		}

		throw new EntityTypeException(
				"Could not resolve entity class '" + javaType.getName() + "'",
				javaType.getName()
		);
	}

	private <T> @Nullable SqmPolymorphicRootDescriptor<T> createPolymorphicRootDescriptor(Class<T> javaType) {
		// create a set of descriptors that should be used to build the polymorphic EntityDomainType
		final Set<EntityDomainType<? extends T>> matchingDescriptors = new HashSet<>();
		for ( var managedType : managedTypeByName.values() ) {
			if ( managedType.getPersistenceType() == Type.PersistenceType.ENTITY
				// see if we should add EntityDomainType as one of the matching descriptors.
				&& javaType.isAssignableFrom( managedType.getJavaType() ) ) {
				// The queried type is assignable from the type of the current entity type.
				// We should add it to the collecting set of matching descriptors. It should
				// be added aside from a few cases...

				// If the managed type has a supertype and the java type is assignable from the super type,
				// do not add the managed type as the supertype itself will get added and the initializers

View on GitHub (pinned to fad1729dce)

Solutions

  1. Pass a class that is annotated @Entity and mapped in the same persistence unit
  2. For polymorphic queries over a hierarchy, make the common supertype an @Entity with an @Inheritance strategy, or query any @Entity subclass — Hibernate builds a polymorphic descriptor when at least one entity subclass is assignable
  3. For interfaces, add at least one @Entity implementation or map the interface as a proxy (@Proxy) so it resolves
  4. Double-check which persistence unit / entity scan the class is actually in

Example fix

// before
CriteriaQuery<Auditable> q = cb.createQuery(Auditable.class); // Auditable is a plain interface
Root<Auditable> r = q.from(Auditable.class); // throws EntityTypeException

// after
@Entity @Inheritance(strategy = InheritanceType.SINGLE_TABLE)
public abstract class Auditable { ... }
// then query the mapped hierarchy root
CriteriaQuery<Auditable> q = cb.createQuery(Auditable.class);
Root<Auditable> r = q.from(Auditable.class);
Defensive patterns

Strategy: validation

Validate before calling

<T> EntityType<T> entityOrThrow(Metamodel metamodel, Class<T> cls) {
  return metamodel.getEntities().stream()
      .filter(e -> cls.equals(e.getJavaType()))
      .map(e -> (EntityType<T>) e)
      .findFirst()
      .orElseThrow(() -> new IllegalArgumentException(
          "Not a mapped entity: " + cls + ". Known: " +
              metamodel.getEntities().stream().map(Type::getJavaType).toList()));
}
// use: entityOrThrow(emf.getMetamodel(), cls) instead of emf.getMetamodel().entity(cls)

Type guard

static boolean isResolvableEntity(Metamodel metamodel, Class<?> cls) {
  if (cls.isAnnotationPresent(jakarta.persistence.Entity.class)) return true;
  // polymorphic fallback: at least one entity subclass assignable
  return metamodel.getEntities().stream().anyMatch(e -> cls.isAssignableFrom(e.getJavaType()));
}

Try / catch

try {
  EntityType<X> t = emf.getMetamodel().entity(cls);
} catch (jakarta.persistence.metamodel.TypeNotFoundException | EntityTypeException e) { // Hibernate: org.hibernate.metamodel.EntityTypeException
  throw new IllegalArgumentException(cls + " is not an entity in this persistence unit; fix the query domain type", e);
}

Prevention

When it happens

Trigger: Calling emf.getMetamodel().entity(NonEntity.class) or criteriaBuilder.createQuery(X.class).from(X.class) where X is a DTO, @MappedSuperclass, or interface with no @Entity implementors; passing a class that lives in another persistence unit; passing java.lang.Object or a projection class as the query domain.

Common situations: Developer expects @MappedSuperclass or a plain interface to behave like a polymorphic @Entity root; a query root class was refactored into a DTO; the class is mapped in a different EntityManagerFactory (multi-PU setup); the entity was excluded from scanning.

Related errors


AI-assisted analysis of hibernate/hibernate-orm@fad1729dce (2026-08-22). Data as JSON: /api/errors/9fad701e2af22829. Report an issue: GitHub.