hibernate/hibernate-orm · error · MappingException
Collection is not an association: ${role}
Error message
Collection is not an association: ${role} What it means
CollectionType.getAssociatedEntityName (CollectionType.java:445-455) returns the element entity name only when the collection's element type is an entity; for collections of basic values or embeddables (@ElementCollection) it throws MappingException 'Collection is not an association: <role>'. The role string is 'EntityFQN.propertyName', which names the exact collection that was treated as a to-many entity association.
Source
Thrown at hibernate-core/src/main/java/org/hibernate/type/CollectionType.java:453
public Joinable getAssociatedJoinable(SessionFactoryImplementor factory)
throws MappingException {
return (Joinable) getPersister( factory );
}
@Override
public boolean isModified(Object old, Object current, boolean[] checkable, SharedSessionContractImplementor session) {
return false;
}
@Override
public String getAssociatedEntityName(SessionFactoryImplementor factory)
throws MappingException {
final var persister = getPersister( factory );
if ( persister.getElementType().isEntityType() ) {
return persister.getElementPersister().getEntityName();
}
else {
throw new MappingException( "Collection is not an association: " + persister.getRole() );
}
}
/**
* Replace the elements of a collection with the elements of another collection.
*
* @param original The 'source' of the replacement elements (where we copy from)
* @param target The target of the replacement elements (where we copy to)
* @param owner The owner of the collection being merged
* @param copyCache The map of elements already replaced.
* @param session The session from which the merge event originated.
* @return The merged collection.
*/
@SuppressWarnings({"rawtypes", "unchecked"})
public Object replaceElements(
Object original,
Object target,
Object owner,View on GitHub (pinned to fad1729dce)
Solutions
- Read the role in the message: <OwnerEntity>.<property> - open that mapping and decide whether the elements are values or entities.
- If elements should be entities, switch to @OneToMany + a target @Entity (and a join table/fk) so the collection really is an association.
- If elements are values, adjust the query/code to treat them as embeddables: join and select value(o.elements) / element fields directly, without asking for an associated entity name.
- In generic walkers, guard with persister.getElementType().isEntityType() before calling getAssociatedEntityName.
Example fix
// before: element collection used like an entity association
@ElementCollection
Set<Tag> tags;
session.createQuery(
"select o from Owner o join o.tags t where t.name = :n", Owner.class); // ok for value paths
// but legacy aliasing / getAssociatedEntityName('tags') throws
// after (if Tag should be an entity association)
@Entity public class Tag { @Id Long id; String name; @ManyToOne Owner owner; }
@OneToMany(mappedBy = "owner")
Set<Tag> tags; // now a real association; joins and aliases work Defensive patterns
Strategy: validation
Validate before calling
// Generic association walkers: check element type before asking for target entity
CollectionPersister cp = ((SessionFactoryImplementor) sessionFactory)
.getMappingMetamodel().getCollectionDescriptor(role);
if (!cp.getElementType().isEntityType()) {
// element collection: join values only, never ask for associated entity name
return Optional.empty();
} Type guard
static boolean isEntityValuedCollection(CollectionPersister cp) {
return cp.getElementType().isEntityType();
} Try / catch
try {
return type.getAssociatedEntityName(factory);
} catch (MappingException e) {
if (e.getMessage().startsWith("Collection is not an association")) {
// fall back to element-level (value) handling for @ElementCollection roles
return handleAsElementCollection(role);
}
throw e;
} Prevention
- Decide per collection whether elements are values (@ElementCollection) or entities (@OneToMany) and query accordingly.
- Guard generic join/alias builders with an elementType().isEntityType() check and log skipped element collections.
When it happens
Trigger: Operations that treat a collection role as an entity association: legacy Criteria createAlias/createCriteria on an @ElementCollection property; HQL/implicit paths that require the associated entity of the collection (e.g. navigating 'o.someEntityField' through element-collection elements as if they were entities); tooling walking CollectionType.getAssociatedEntityName for every collection role; mistakenly mapping what should be an @OneToMany as @ElementCollection of @Embeddable and then joining on entity fields.
Common situations: Embeddable value objects later promoted to entities while the mapping stays @ElementCollection; generic join builders and specification APIs aliasing every plural attribute; Envers/report queries asking for the 'target entity' of each collection; renaming element classes so developers assume entity semantics.
Related errors
- Property '${property}' defines a collection table '${collect
- @TargetEmbeddable can only be specified on properties marked
- Secondary table (<join/>) must explicitly name table or sub-
- collection element mappingContext has wrong number of column
- An association from the table '" + getTable().getName() + "'
AI-assisted analysis of hibernate/hibernate-orm@fad1729dce (2026-08-22).
Data as JSON: /api/errors/a34363f7b59c278f.
Report an issue: GitHub.