hibernate/hibernate-orm · error · AnnotationException

Custom type '%s' implements 'AnnotationBasedUserType' but no

Error message

Custom type '%s' implements 'AnnotationBasedUserType' but no custom type annotation is present

What it means

UserTypes implementing AnnotationBasedUserType<A, ?> are initialized with the type annotation found on the mapped attribute. When no such annotation is present (typeAnnotation == null), Hibernate throws AnnotationException naming the custom type class, since initialize(...) cannot run without configuration.

Source

Thrown at hibernate-core/src/main/java/org/hibernate/mapping/BasicValue.java:1155

			initializeAnnotationBasedUserType( typeAnnotation, annotationBased, creationContext );
		}
		return typeInstance;
	}

	private void addParameterType(Properties properties, UserType<?> typeInstance) {
		if ( typeInstance instanceof DynamicParameterizedType
				&& parseBoolean( properties.getProperty( DynamicParameterizedType.IS_DYNAMIC ) )
				&& properties.get( DynamicParameterizedType.PARAMETER_TYPE ) == null ) {
			properties.put( DynamicParameterizedType.PARAMETER_TYPE, createParameterType() );
		}
	}

	private <A extends Annotation> void initializeAnnotationBasedUserType(
			Annotation typeAnnotation,
			AnnotationBasedUserType<A, ?> annotationBased,
			UserTypeCreationContext creationContext) {
		if ( typeAnnotation == null ) {
			throw new AnnotationException( String.format(
					"Custom type '%s' implements 'AnnotationBasedUserType' but no custom type annotation is present",
					annotationBased.getClass().getName() ) );
		}
		annotationBased.initialize( castAnnotationType( typeAnnotation, annotationBased ), creationContext );
	}

	private class TypeCreationContext implements UserTypeCreationContext {
		private final Properties parameters;

		private TypeCreationContext(Properties parameters) {
			this.parameters = parameters;
		}

		@Override
		public MetadataBuildingContext getBuildingContext() {
			return BasicValue.this.getBuildingContext();
		}

View on GitHub (pinned to fad1729dce)

Solutions

  1. Annotate the attribute with the annotation the custom type declares (e.g., @MyAnn with its parameters).
  2. If the type needs no annotation configuration, drop AnnotationBasedUserType from its interfaces.
  3. When applying types centrally, also transfer the expected annotation onto each attribute.

Example fix

// before: type implements AnnotationBasedUserType<Formatted, ?>
@CustomType(FormattedStringType.class)
private String note;

// after
@Formatted(uppercase = true)
@CustomType(FormattedStringType.class)
private String note;
Defensive patterns

Strategy: validation

Validate before calling

static boolean annotationPresent( Field f, Class<? extends Annotation> expected ) {
    return f.isAnnotationPresent( expected );
}
// for each @CustomType attribute, assert the annotation declared by its AnnotationBasedUserType is present

Prevention

When it happens

Trigger: @CustomType(MyType.class) where MyType implements AnnotationBasedUserType<MyAnn, ?> but the attribute carries no @MyAnn; registering such a type via plain @Type/@TypeDef so the annotation never reaches it; attribute carrying only unrelated annotations.

Common situations: Adopting Hibernate 6.2+ annotation-based custom types incrementally; frameworks applying custom types centrally without the paired annotation; copying a custom type declaration without its annotation.

Related errors


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