{"record":{"id":"dd2dfe861a998966","repo":"quarkusio/quarkus","slug":"entity-generic-argument-of-repository-is-not-a","errorCode":null,"errorMessage":"Entity generic argument of ${repository} is not a regular class type","messagePattern":"Entity generic argument of (.+?) is not a regular class type","errorType":"exception","errorClass":"IllegalArgumentException","httpStatus":null,"severity":"error","filePath":"extensions/spring-data-jpa/deployment/src/main/java/io/quarkus/spring/data/deployment/generate/SpringDataRepositoryCreator.java","lineNumber":154,"sourceCode":"\n    private Map.Entry<DotName, DotName> extractIdAndEntityTypes(ClassInfo repositoryToImplement, IndexView indexView) {\n        AnnotationInstance repositoryDefinitionInstance = repositoryToImplement\n                .declaredAnnotation(DotNames.SPRING_DATA_REPOSITORY_DEFINITION);\n        if (repositoryDefinitionInstance != null) {\n            return new AbstractMap.SimpleEntry<>(repositoryDefinitionInstance.value(\"idClass\").asClass().name(),\n                    repositoryDefinitionInstance.value(\"domainClass\").asClass().name());\n        }\n\n        DotName entityDotName = null;\n        DotName idDotName = null;\n\n        // we need to pull the entity and ID types for the Spring Data generic types\n        // we also need to make sure that the user didn't try to specify multiple different types\n        // in the same interface (which is possible if only Repository is used)\n        for (DotName extendedSpringDataRepo : GenerationUtil.extendedSpringDataRepos(repositoryToImplement, indexView)) {\n            List<Type> types = JandexUtil.resolveTypeParameters(repositoryToImplement.name(), extendedSpringDataRepo, index);\n            if (!(types.get(0) instanceof ClassType)) {\n                throw new IllegalArgumentException(\n                        \"Entity generic argument of \" + repositoryToImplement + \" is not a regular class type\");\n            }\n            DotName newEntityDotName = types.get(0).name();\n            if ((entityDotName != null) && !newEntityDotName.equals(entityDotName)) {\n                throw new IllegalArgumentException(\"Repository \" + repositoryToImplement + \" specifies multiple Entity types\");\n            }\n            entityDotName = newEntityDotName;\n\n            DotName newIdDotName = types.get(1).name();\n            if ((idDotName != null) && !newIdDotName.equals(idDotName)) {\n                throw new IllegalArgumentException(\"Repository \" + repositoryToImplement + \" specifies multiple ID types\");\n            }\n            idDotName = newIdDotName;\n        }\n\n        if (idDotName == null || entityDotName == null) {\n            throw new IllegalArgumentException(\n                    \"Repository \" + repositoryToImplement + \" does not specify ID and/or Entity type\");","sourceCodeStart":136,"sourceCodeEnd":172,"githubUrl":"https://github.com/quarkusio/quarkus/blob/e1c734241f34c7919086ceb4c9262b4a58f6de44/extensions/spring-data-jpa/deployment/src/main/java/io/quarkus/spring/data/deployment/generate/SpringDataRepositoryCreator.java#L136-L172","documentation":"Quarkus resolves the repository's <E, ID> generic parameters against the extended Spring Data interface. The entity argument (first type parameter) must be a plain class type; type variables, wildcards, parameterized or array types cannot be used to generate queries. This error is thrown when the resolved entity argument is not a ClassType.","triggerScenarios":"Declaring a repository whose first generic argument is a type variable, wildcard, generic type (e.g. Repo<T, Long> inside a generic superclass), or otherwise non-class type instead of a concrete @Entity class.","commonSituations":"Wrapping repositories in generic base classes/interfaces; using wildcards like CrudRepository<? extends Foo, Long>; intermediate generic layers where the entity type remains unresolved.","solutions":["Make the repository's entity argument a concrete class: extends CrudRepository<MyEntity, Long>","Remove generic intermediate layers or ensure the concrete type is resolved at the final repository interface (not left as a type variable)","Do not use wildcards or parameterized types as the entity argument"],"exampleFix":"// before\nclass BaseRepo<T, ID> extends CrudRepository<T, ID> { }\ninterface FooRepo extends BaseRepo<Foo, Long> { } // resolution may still see T in some layouts\n// after\ninterface FooRepo extends CrudRepository<Foo, Long> { }","handlingStrategy":"validation","validationCode":"// Entity argument must be a concrete class\ninterface UserRepo extends CrudRepository<User, Long> { } // good\n// avoid: CrudRepository<? extends User, Long> or generic bases resolving to type variables","typeGuard":"Class<?> entityType(Object repoGenericArg) {\n    return (repoGenericArg instanceof Class<?> c && !c.isInterface() && !c.getTypeParameters().length.isArrayType()) ? c : null;\n}","tryCatchPattern":null,"preventionTips":["Never parameterize repositories with wildcards or type variables","Flatten generic base repository hierarchies into concrete interfaces","Resolve generics at the leaf repository interface"],"tags":["quarkus","spring-data-jpa","generics","build-time"],"backgroundTag":"invalid-generic-type-parameter","analyzedSha":"e1c734241f34c7919086ceb4c9262b4a58f6de44","analyzedAt":"2026-09-05T17:01:29.979Z","contentChangedAt":"2026-09-05T17:01:29.979Z","schemaVersion":2},"datasetVersion":"2026-09-12T22:17:10.623Z"}