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

  1. Read the role in the message: <OwnerEntity>.<property> - open that mapping and decide whether the elements are values or entities.
  2. If elements should be entities, switch to @OneToMany + a target @Entity (and a join table/fk) so the collection really is an association.
  3. 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.
  4. 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

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


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