hibernate/hibernate-orm · critical · HibernateException

Multiple entities [%s, %s] named the same interface [%s] as

Error message

Multiple entities [%s, %s] named the same interface [%s] as their proxy which is not supported

What it means

During MappingMetamodel bootstrap Hibernate indexes each entity's proxy interface in entityProxyInterfaceMap (used to resolve entities by class later). If two different entities register the SAME interface as their concrete proxy class, the inverse lookup becomes ambiguous and HibernateException is thrown at SessionFactory creation.

Source

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

			final String className = model.getClassName();
			if ( className != null && !className.equals( entityName ) ) {
				// But only if the class name is not registered already,
				// as we can have the same class mapped to multiple entity names
				entityPersisterMap.putIfAbsent( className, entityPersister );
			}

			final var concreteProxyClass = entityPersister.getConcreteProxyClass();
			final var mappedClass = entityPersister.getMappedClass();
			if ( concreteProxyClass != null
					&& concreteProxyClass.isInterface()
					// we exclude Map-based proxy interfaces here because that should indicate MAP entity mode
					&& !Map.class.isAssignableFrom( concreteProxyClass )
					&& mappedClass != concreteProxyClass ) {
				final String existing =
						entityProxyInterfaceMap.put( concreteProxyClass,
								entityPersister.getEntityName() );
				if ( existing != null ) {
					throw new HibernateException(
							String.format(
									Locale.ENGLISH,
									"Multiple entities [%s, %s] named the same interface [%s] as their proxy which is not supported",
									existing,
									entityPersister.getEntityName(),
									concreteProxyClass.getName()
							)
					);
				}
			}
		}
	}

	private void processBootCollections(
			java.util.Collection<Collection> collectionBindings,
			CacheImplementor cacheImplementor,
			PersisterFactory persisterFactory,
			RuntimeModelCreationContext modelCreationContext) {

View on GitHub (pinned to fad1729dce)

Solutions

  1. Give each entity its own distinct proxy interface and reference it in @Proxy(proxyClass=...)
  2. Drop @Proxy on the entity to fall back to default class-based proxies
  3. If the shared type must be the polymorphic handle, make it the @Entity hierarchy root instead of a proxy interface on siblings

Example fix

// before
public interface Identifiable { Long getId(); }
@Entity @Proxy(proxyClass = Identifiable.class) public class Article implements Identifiable {...}
@Entity @Proxy(proxyClass = Identifiable.class) public class Comment implements Identifiable {...} // duplicate -> HibernateException

// after
@Entity public class Article implements Identifiable {...}
@Entity public class Comment implements Identifiable {...} // no @Proxy, default proxies
Defensive patterns

Strategy: try-catch

Validate before calling

// Static pre-flight: detect duplicate proxy interfaces across mapped entities before EMF build
Map<Class<?>, String> byInterface = new HashMap<>();
for (Class<?> c : scannedEntityClasses) {
  org.hibernate.annotations.Proxy proxy = c.getAnnotation(org.hibernate.annotations.Proxy.class);
  if (proxy != null && proxy.proxyClass().isInterface()) {
    String prev = byInterface.put(proxy.proxyClass(), c.getName());
    if (prev != null) {
      throw new IllegalStateException("Proxy interface " + proxy.proxyClass()
          + " used by both " + prev + " and " + c.getName());
    }
  }
}

Try / catch

try {
  sessionFactory = new Configuration().addAnnotatedClass(...).buildSessionFactory();
} catch (HibernateException e) {
  if (e.getMessage() != null && e.getMessage().contains("named the same interface")) {
    // two entities share one @Proxy interface — give each entity its own proxy interface or drop @Proxy
    throw new IllegalStateException("Duplicate proxy interface between entities: " + e.getMessage(), e);
  }
  throw e;
}

Prevention

When it happens

Trigger: Two entities each declare @Proxy(proxyClass = SameInterface.class) (or otherwise end up with the same interface as concreteProxyClass while mappedClass differs, excluding Map-based MAP entity mode); e.g. an interface 'Auditable' used as proxy on both Article and Comment.

Common situations: Copy-pasted @Proxy annotations across entities implementing a shared domain interface; introducing @Proxy on a second implementation of an existing proxy interface; consolidating entities that accidentally share a marker interface as proxy.

Related errors


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