hibernate/hibernate-orm · error · MappingException
Basic array has element type '" + componentJavaType.getTypeN
Error message
Basic array has element type '" + componentJavaType.getTypeName() + "' which is not a known basic type (attribute is not annotated '@ElementCollection', '@OneToMany', or '@ManyToMany')
What it means
Thrown when Hibernate must pick a JDBC type for a basic array attribute (AbstractArrayJavaType.getRecommendedJdbcType) but the element's JavaType is UnknownBasicJavaType - meaning the component class has no registered basic type. The message reminds you that non-basic element collections must be mapped as @ElementCollection/@OneToMany/@ManyToMany, not as plain arrays.
Source
Thrown at hibernate-core/src/main/java/org/hibernate/type/descriptor/java/AbstractArrayJavaType.java:44
public abstract class AbstractArrayJavaType<T, E> extends AbstractClassJavaType<T>
implements BasicPluralJavaType<E> {
private final JavaType<E> componentJavaType;
public AbstractArrayJavaType(Class<T> clazz, JavaType<E> baseDescriptor, MutabilityPlan<T> mutabilityPlan) {
super( clazz, mutabilityPlan );
this.componentJavaType = baseDescriptor;
}
@Override
public JavaType<E> getElementJavaType() {
return componentJavaType;
}
@Override
public JdbcType getRecommendedJdbcType(JdbcTypeIndicators indicators) {
if ( componentJavaType instanceof UnknownBasicJavaType) {
throw new MappingException("Basic array 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
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
);
}
@Override
public boolean isWider(JavaType<?> javaType) {
// Support binding single element valueView on GitHub (pinned to fad1729dce)
Solutions
- Annotate the field with @ElementCollection (targetClass = element type) so it is mapped as a collection, not a basic array
- Change the element type to a known basic type (String, Integer, UUID, enum with @Enumerated, ...)
- Register a JavaType/BasicType for the custom element class via @JavaTypeRegistration on the entity or a TypeContributor
- Map the array explicitly with @JdbcTypeCode(SqlTypes.ARRAY) plus a registered element type
Example fix
// before
@Entity
public class Doc {
private Tag[] tags; // Tag is not a known basic type -> MappingException
}
// after
@Entity
public class Doc {
@ElementCollection(targetClass = String.class)
@Column(name = "tags")
private String[] tags;
}
// or: map Tag as a basic type via @JavaTypeRegistration and keep Tag[] with @JdbcTypeCode(SqlTypes.ARRAY) Defensive patterns
Strategy: validation
Validate before calling
// in a @PrePersist/@PreUpdate-free mapping test (or bootstrap check):
// assert every array-typed persistent field has a basic element type or collection annotations
for (Field f : entityClass.getDeclaredFields()) {
Class<?> elem = f.getType().getComponentType();
if (elem != null && !isBasicType(elem)
&& !f.isAnnotationPresent(ElementCollection.class)) {
throw new MappingException("Unannotated array of non-basic type: " + f);
}
} Type guard
static boolean isKnownBasicElement(Class<?> c) {
return c.isPrimitive() || c == String.class || c.isEnum()
|| Number.class.isAssignableFrom(c)
|| java.time.temporal.Temporal.class.isAssignableFrom(c);
} Try / catch
try {
sessionFactory = new MetadataSources(registry).addAnnotatedClass(Doc.class)
.buildMetadata().buildSessionFactory();
} catch (MappingException e) {
if (String.valueOf(e.getMessage()).contains("not a known basic type")) {
// annotate as @ElementCollection or register a JavaType for the element class
} else throw e;
} Prevention
- Always annotate plural-of-embeddable fields with @ElementCollection
- Prefer List<Element> + @ElementCollection over bare arrays of custom types
- Cover mappings with a bootstrap test that builds the SessionFactory in CI
- Register custom element types via @JavaTypeRegistration before using them in arrays
When it happens
Trigger: An entity field like MyCustomType[] values or List<SomeEmbeddable> mapped as a basic array (dialect supports arrays, no collection annotations present) where the element class is not a known basic type; e.g. arrays of enums with custom mapping, arrays of Value Objects, or embeddables without @ElementCollection.
Common situations: Migrating to Hibernate 6/7 where basic array support was introduced and unannotated array fields stopped being treated as element collections; PostgreSQL array columns of custom types; forgetting @ElementCollection on a List<embeddable> field; element type lacking a BasicType registration.
Related errors
- Unable to determine JDBC type for converted parameter relati
- getTypeName() + " as TemporalType.TIMESTAMP not supported"
- getTypeName() + " as TemporalType.DATE not supported"
- getTypeName() + " as TemporalType.TIME not supported"
- Duplicate named query '%s'
AI-assisted analysis of hibernate/hibernate-orm@fad1729dce (2026-08-22).
Data as JSON: /api/errors/6b180d5e88e20ba5.
Report an issue: GitHub.