hibernate/hibernate-orm · error · MappingException
Basic collection has element type '%s' which is not a known
Error message
Basic collection has element type '%s' which is not a known basic type (attribute is not annotated '@ElementCollection', '@OneToMany', or '@ManyToMany')
What it means
BasicCollectionJavaType models a List/Set treated as one basic value (e.g. an array-mapped column). Before choosing a JDBC type it must resolve the element type; if the element's JavaType is UnknownBasicJavaType, Hibernate has no mapping for it and bootstrap fails with this MappingException. The message itself hints the cause: the attribute probably needed @ElementCollection/@OneToMany/@ManyToMany semantics instead of basic-collection semantics.
Source
Thrown at hibernate-core/src/main/java/org/hibernate/type/descriptor/java/spi/BasicCollectionJavaType.java:76
private final CollectionSemantics<C, E> semantics;
private final JavaType<E> componentJavaType;
public BasicCollectionJavaType(ParameterizedType type, JavaType<E> componentJavaType, CollectionSemantics<C, E> semantics) {
super( type, new CollectionMutabilityPlan<>( componentJavaType, semantics ) );
this.semantics = semantics;
this.componentJavaType = componentJavaType;
}
@Override
public JavaType<E> getElementJavaType() {
return componentJavaType;
}
@Override
public JdbcType getRecommendedJdbcType(JdbcTypeIndicators indicators) {
if ( componentJavaType instanceof UnknownBasicJavaType ) {
throw new MappingException("Basic collection has element type '"
+ componentJavaType.getTypeName()
+ "' which is not a known basic type"
+ " (attribute is not annotated '@ElementCollection', '@OneToMany', or '@ManyToMany')");
}
// Always determine the recommended type to make sure this is a valid basic java type
// (even though we only use this inside the if block, we want it to throw here if something wrong)
final var recommendedComponentJdbcType = componentJavaType.getRecommendedJdbcType( indicators );
final var typeConfiguration = indicators.getTypeConfiguration();
return typeConfiguration.getJdbcTypeRegistry()
.resolveTypeConstructorDescriptor(
indicators.getPreferredSqlTypeCodeForArray( recommendedComponentJdbcType.getDefaultSqlTypeCode() ),
typeConfiguration.getBasicTypeRegistry().resolve( componentJavaType, recommendedComponentJdbcType ),
ColumnTypeInformation.EMPTY
);
}
public CollectionSemantics<C, E> getSemantics() {
return semantics;View on GitHub (pinned to fad1729dce)
Solutions
- Add @ElementCollection to collections of basic or embeddable elements
- Use @OneToMany/@ManyToMany when the elements are entities
- Register a JavaType for the element class via @JavaTypeRegistration or MetadataBuilder.applyBasicType so it is no longer 'unknown'
- For custom value classes, add an AttributeConverter to a supported basic type (String, int, ...) which supplies the JDBC side implicitly
Example fix
// before
@Entity class Doc {
@JdbcTypeCode(SqlTypes.ARRAY)
@Column(name = "tags")
List<String> tags = new ArrayList<>(); // element resolves to UnknownBasicJavaType -> MappingException
}
// after
@Entity class Doc {
@ElementCollection
@JdbcTypeCode(SqlTypes.ARRAY)
@Column(name = "tags")
List<String> tags = new ArrayList<>();
} Defensive patterns
Strategy: validation
Validate before calling
static List<String> collectionFieldsMissingAnnotations(Class<?>... entities) {
var missing = new ArrayList<String>();
for (var e : entities)
for (var f : e.getDeclaredFields())
if (java.util.Collection.class.isAssignableFrom(f.getType())
&& !f.isAnnotationPresent(jakarta.persistence.ElementCollection.class)
&& !f.isAnnotationPresent(jakarta.persistence.OneToMany.class)
&& !f.isAnnotationPresent(jakarta.persistence.ManyToMany.class)
&& !f.isAnnotationPresent(jakarta.persistence.Transient.class))
missing.add(e.getName() + "." + f.getName());
return missing; // assert empty before buildSessionFactory()
} Try / catch
try {
sessionFactory = metadata.buildSessionFactory();
} catch (org.hibernate.MappingException e) {
// message names the element type; fix the annotation or registration, then rebuild
throw new IllegalStateException("Mapping bootstrap failed: " + e.getMessage(), e);
} Prevention
- Annotate every persistent collection with @ElementCollection, @OneToMany or @ManyToMany
- Always declare concrete element generics — never raw collections
- Register custom element types with @JavaTypeRegistration before enabling array mapping
- Bootstrap the SessionFactory in CI so mapping errors surface pre-deploy
When it happens
Trigger: A collection attribute mapped as a single basic value (@JdbcTypeCode(SqlTypes.ARRAY), @Array, or plain unannotated collection) whose element type — a custom class, Object, or unresolvable generic — has no registered basic JavaType; entity-valued collections missing their relationship annotation so elements resolve as unknown basics.
Common situations: Forgetting @ElementCollection on a List<String>/List<enum> mapped to an array column in Hibernate 6.x; trying to persist List<OwnClass> without registering a type for OwnClass; raw collection fields without generics; annotation imports missing so @OneToMany silently does not apply.
Related errors
- @TargetEmbeddable can only be specified on properties marked
- collection id mapping has wrong number of columns: " + getRo
- collection index mapping has wrong number of columns: " + ge
- Unsupported attempt to resolve JDBC type for Map.Entry
- Named query definition is null
AI-assisted analysis of hibernate/hibernate-orm@fad1729dce (2026-08-22).
Data as JSON: /api/errors/3fcc14ece46ea6ad.
Report an issue: GitHub.