hibernate/hibernate-orm · error · AnnotationException
Attribute '${attribute}' is declared as an '@Id' or '@Embedd
Error message
Attribute '${attribute}' is declared as an '@Id' or '@EmbeddedId' property by '${declaringType}' and so '${respecifyingType}' may not respecify the generation strategy What it means
When an @Id is already declared by a superclass (typically a @MappedSuperclass) and a subclass re-specifies the generation strategy — via @GeneratedValue or an @IdGeneratorType-meta-annotated generator — Hibernate rejects the override: generation settings may only be declared where the identifier is declared. This is a deliberate limitation (see the TODO in the source) because reliably detecting a legitimate root-entity override is not currently possible.
Source
Thrown at hibernate-core/src/main/java/org/hibernate/boot/model/internal/PropertyBinder.java:773
collector.addPropertyAnnotatedWithMapsId( ownerType.determineRawClass(), propertyAnnotatedElement );
}
return idPropertyCounter;
}
private static void checkIdProperty(MemberDetails property, PropertyData propertyData, ModelsContext context) {
final boolean incomingIdProperty = hasIdAnnotation( property );
if ( incomingIdProperty ) {
final var memberDetails = propertyData.getAttributeMember();
final boolean existingIdProperty = hasIdAnnotation( memberDetails );
if ( existingIdProperty ) {
if ( property.hasDirectAnnotationUsage( GeneratedValue.class )
|| !property.getMetaAnnotated( IdGeneratorType.class, context ).isEmpty() ) {
//TODO: it would be nice to allow a root @Entity to override an
// @Id field declared by a @MappedSuperclass and change the
// generator, but for now we don't seem to be able to detect
// that case here
throw new AnnotationException(
"Attribute '" + memberDetails.getName()
+ "' is declared as an '@Id' or '@EmbeddedId' property by '"
+ memberDetails.getDeclaringType().getName()
+ "' and so '" + property.getDeclaringType().getName()
+ "' may not respecify the generation strategy" );
}
}
else {
//TODO: it would be nice to allow a root @Entity to override a
// field declared by a @MappedSuperclass, redeclaring it
// as an @Id field, but for now we don't seem to be able
// to detect that case here
throw new AnnotationException(
"Attribute '" + memberDetails.getName()
+ "' is declared by '" + memberDetails.getDeclaringType().getName()
+ "' and may not be redeclared as an '@Id' or '@EmbeddedId' by '"
+ property.getDeclaringType().getName() + "'" );
}View on GitHub (pinned to fad1729dce)
Solutions
- Remove @GeneratedValue (and any @IdGeneratorType annotation) from the subclass override — keep the generator only on the superclass declaration.
- If subclasses need different strategies, declare the @Id (with its generator) separately in each concrete root entity instead of inheriting one declaration.
- Use a shared @MappedSuperclass WITHOUT @GeneratedValue and put @GeneratedValue on each entity's own @Id if it must redeclare; ensure only one level declares the generator.
Example fix
// before
@MappedSuperclass
public abstract class BaseEntity {
@Id
protected Long id;
}
@Entity
public class Order extends BaseEntity {
@Override
@Id
@GeneratedValue(strategy = GenerationType.SEQUENCE) // rejected
public Long getId() { return id; }
}
// after: generator lives with the declaration
@MappedSuperclass
public abstract class BaseEntity {
@Id
@GeneratedValue(strategy = GenerationType.SEQUENCE)
protected Long id;
} Defensive patterns
Strategy: validation
Validate before calling
// A subclass override of an inherited @Id must not add a generator
for (Class<?> entity : annotatedClasses) {
Class<?> sup = entity.getSuperclass();
while (sup != null && sup.isAnnotationPresent(MappedSuperclass.class)) {
for (Field supF : sup.getDeclaredFields()) {
if (!supF.isAnnotationPresent(Id.class)) continue;
try {
Field own = entity.getDeclaredField(supF.getName());
if (own.isAnnotationPresent(GeneratedValue.class)) {
throw new IllegalStateException(entity.getName() + " may not respecify generator for inherited id " + own.getName());
}
} catch (NoSuchFieldException ignored) { }
}
sup = sup.getSuperclass();
}
} Try / catch
try {
SessionFactory sf = cfg.buildSessionFactory();
} catch (AnnotationException e) {
throw new IllegalStateException("Id generation redefinition: " + e.getMessage(), e);
} Prevention
- Declare @GeneratedValue exactly once, where the @Id is declared
- If per-entity strategies are needed, don't inherit the id from a mapped superclass
When it happens
Trigger: A @MappedSuperclass Base declares @Id Long id; the concrete entity redeclares the field with @Id @GeneratedValue(strategy = ...), or adds @GeneratedValue / a custom @IdGeneratorType annotation on the overriding attribute; @AttributeOverride-style field overrides that carry a generator.
Common situations: Abstract base entities with a shared @Id where some subclasses want IDENTITY and others SEQUENCE; introducing a generator on a subclass after inheriting the plain id; framework patterns (Spring Data reference templates) that re-annotate inherited id fields.
Related errors
- Attribute '" + memberDetails.getName() + "' is declared by '
- Mapped superclass '{}' may not specify an '@Inheritance' map
- Property '${property}' belongs to an entity subclass and may
- Property '${property}' is annotated '@OptimisticLock(exclude
- Member '" + memberDetails.getName() + "' of embeddable class
AI-assisted analysis of hibernate/hibernate-orm@fad1729dce (2026-08-22).
Data as JSON: /api/errors/2db5968f002ebda1.
Report an issue: GitHub.