diff --git a/mapper/javabean/src/main/java/org/hibernate/search/mapper/javabean/log/impl/Log.java b/mapper/javabean/src/main/java/org/hibernate/search/mapper/javabean/log/impl/Log.java
index bb17990597..c89ce70e1f 100644
--- a/mapper/javabean/src/main/java/org/hibernate/search/mapper/javabean/log/impl/Log.java
+++ b/mapper/javabean/src/main/java/org/hibernate/search/mapper/javabean/log/impl/Log.java
@@ -8,8 +8,6 @@
 package org.hibernate.search.mapper.javabean.log.impl;
 
 import org.hibernate.search.engine.backend.common.DocumentReference;
-import org.hibernate.search.mapper.pojo.logging.spi.PojoTypeModelFormatter;
-import org.hibernate.search.mapper.pojo.model.spi.PojoRawTypeModel;
 import org.hibernate.search.util.common.SearchException;
 import org.hibernate.search.util.common.logging.impl.MessageConstants;
 import org.hibernate.search.util.common.logging.impl.ClassFormatter;
@@ -27,17 +25,9 @@
 
 	int ID_OFFSET_1 = MessageConstants.MAPPER_JAVABEAN_ID_RANGE_MIN;
 
-	@Message(id = ID_OFFSET_1 + 1,
-			value = "Unable to find property '%2$s' on type '%1$s'.")
-	SearchException cannotFindProperty(@FormatWith(PojoTypeModelFormatter.class) PojoRawTypeModel<?> typeModel,
-			String propertyName);
-
 	@Message(id = ID_OFFSET_1 + 3, value = "Exception while retrieving the type model for '%1$s'.")
 	SearchException errorRetrievingTypeModel(@FormatWith(ClassFormatter.class) Class<?> clazz, @Cause Exception cause);
 
-	@Message(id = ID_OFFSET_1 + 4, value = "Exception while retrieving property type model for '%1$s' on '%2$s'")
-	SearchException errorRetrievingPropertyTypeModel(String propertyModelName, @FormatWith(PojoTypeModelFormatter.class) PojoRawTypeModel<?> parentTypeModel, @Cause Exception cause);
-
 	@Message(id = ID_OFFSET_1 + 5,
 			value = "The JavaBean mapper cannot load entities,"
 					+ " but there was an attempt to load the entity corresponding to document '%1$s'."
diff --git a/mapper/javabean/src/main/java/org/hibernate/search/mapper/javabean/model/impl/JavaBeanBootstrapIntrospector.java b/mapper/javabean/src/main/java/org/hibernate/search/mapper/javabean/model/impl/JavaBeanBootstrapIntrospector.java
index 442c3697db..6e3e23a4ac 100644
--- a/mapper/javabean/src/main/java/org/hibernate/search/mapper/javabean/model/impl/JavaBeanBootstrapIntrospector.java
+++ b/mapper/javabean/src/main/java/org/hibernate/search/mapper/javabean/model/impl/JavaBeanBootstrapIntrospector.java
@@ -7,20 +7,24 @@
 package org.hibernate.search.mapper.javabean.model.impl;
 
 import java.lang.invoke.MethodHandles;
+import java.lang.reflect.AccessibleObject;
+import java.lang.reflect.Field;
+import java.lang.reflect.Member;
 import java.lang.reflect.Method;
+import java.lang.reflect.Modifier;
 import java.util.HashMap;
 import java.util.Map;
-import java.util.stream.Stream;
 
-import org.hibernate.annotations.common.reflection.XClass;
 import org.hibernate.annotations.common.reflection.java.JavaReflectionManager;
 import org.hibernate.search.mapper.javabean.log.impl.Log;
 import org.hibernate.search.mapper.pojo.model.hcann.spi.AbstractPojoHCAnnBootstrapIntrospector;
+import org.hibernate.search.mapper.pojo.model.hcann.spi.PojoHCannOrmGenericContextHelper;
 import org.hibernate.search.mapper.pojo.model.spi.GenericContextAwarePojoGenericTypeModel.RawTypeDeclaringContext;
 import org.hibernate.search.mapper.pojo.model.spi.PojoBootstrapIntrospector;
 import org.hibernate.search.mapper.pojo.model.spi.PojoGenericTypeModel;
 import org.hibernate.search.mapper.pojo.model.spi.PojoRawTypeIdentifier;
 import org.hibernate.search.mapper.pojo.model.spi.PojoRawTypeModel;
+import org.hibernate.search.util.common.AssertionFailure;
 import org.hibernate.search.util.common.impl.ReflectionHelper;
 import org.hibernate.search.util.common.logging.impl.LoggerFactory;
 import org.hibernate.search.util.common.reflect.spi.ValueReadHandle;
@@ -42,7 +46,7 @@ public static JavaBeanBootstrapIntrospector create(MethodHandles.Lookup lookup)
 	}
 
 	private final ValueReadHandleFactory valueReadHandleFactory;
-	private final JavaBeanGenericContextHelper genericContextHelper;
+	private final PojoHCannOrmGenericContextHelper genericContextHelper;
 	private final RawTypeDeclaringContext<?> missingRawTypeDeclaringContext;
 
 	private final Map<Class<?>, PojoRawTypeModel<?>> typeModelCache = new HashMap<>();
@@ -50,7 +54,7 @@ public static JavaBeanBootstrapIntrospector create(MethodHandles.Lookup lookup)
 	private JavaBeanBootstrapIntrospector(ValueReadHandleFactory valueReadHandleFactory) {
 		super( new JavaReflectionManager() );
 		this.valueReadHandleFactory = valueReadHandleFactory;
-		this.genericContextHelper = new JavaBeanGenericContextHelper( this );
+		this.genericContextHelper = new PojoHCannOrmGenericContextHelper( this );
 		this.missingRawTypeDeclaringContext = new RawTypeDeclaringContext<>(
 				genericContextHelper, Object.class
 		);
@@ -58,7 +62,7 @@ private JavaBeanBootstrapIntrospector(ValueReadHandleFactory valueReadHandleFact
 
 	@Override
 	@SuppressWarnings("unchecked")
-	public <T> JavaBeanTypeModel<T> typeModel(Class<T> clazz) {
+	public <T> JavaBeanRawTypeModel<T> typeModel(Class<T> clazz) {
 		if ( clazz.isPrimitive() ) {
 			/*
 			 * We'll never manipulate the primitive type, as we're using generics everywhere,
@@ -66,7 +70,7 @@ private JavaBeanBootstrapIntrospector(ValueReadHandleFactory valueReadHandleFact
 			 */
 			clazz = (Class<T>) ReflectionHelper.getPrimitiveWrapperType( clazz );
 		}
-		return (JavaBeanTypeModel<T>) typeModelCache.computeIfAbsent( clazz, this::createTypeModel );
+		return (JavaBeanRawTypeModel<T>) typeModelCache.computeIfAbsent( clazz, this::createTypeModel );
 	}
 
 	@Override
@@ -84,22 +88,26 @@ public ValueReadHandleFactory annotationValueReadHandleFactory() {
 		return valueReadHandleFactory;
 	}
 
-	Stream<? extends JavaBeanTypeModel<?>> getAscendingSuperTypes(XClass xClass) {
-		return ascendingSuperClasses( xClass ).map( this::typeModel );
-	}
-
-	Stream<? extends JavaBeanTypeModel<?>> getDescendingSuperTypes(XClass xClass) {
-		return descendingSuperClasses( xClass ).map( this::typeModel );
-	}
-
-	ValueReadHandle<?> createValueReadHandle(Method method) throws IllegalAccessException {
-		return valueReadHandleFactory.createForMethod( method );
+	ValueReadHandle<?> createValueReadHandle(Member member) throws IllegalAccessException {
+		if ( member instanceof Method ) {
+			Method method = (Method) member;
+			setAccessible( method );
+			return valueReadHandleFactory.createForMethod( method );
+		}
+		else if ( member instanceof Field ) {
+			Field field = (Field) member;
+			setAccessible( field );
+			return valueReadHandleFactory.createForField( field );
+		}
+		else {
+			throw new AssertionFailure( "Unexpected type for a " + Member.class.getName() + ": " + member );
+		}
 	}
 
 	private <T> PojoRawTypeModel<T> createTypeModel(Class<T> clazz) {
 		PojoRawTypeIdentifier<T> typeIdentifier = PojoRawTypeIdentifier.of( clazz );
 		try {
-			return new JavaBeanTypeModel<>(
+			return new JavaBeanRawTypeModel<>(
 					this, typeIdentifier,
 					new RawTypeDeclaringContext<>( genericContextHelper, clazz )
 			);
@@ -108,4 +116,17 @@ public ValueReadHandleFactory annotationValueReadHandleFactory() {
 			throw log.errorRetrievingTypeModel( clazz, e );
 		}
 	}
+
+	private static void setAccessible(AccessibleObject member) {
+		try {
+			// always set accessible to true as it bypasses the security model checks
+			// at execution time and is faster.
+			member.setAccessible( true );
+		}
+		catch (SecurityException se) {
+			if ( !Modifier.isPublic( ( (Member) member ).getModifiers() ) ) {
+				throw se;
+			}
+		}
+	}
 }
diff --git a/mapper/javabean/src/main/java/org/hibernate/search/mapper/javabean/model/impl/JavaBeanGenericContextHelper.java b/mapper/javabean/src/main/java/org/hibernate/search/mapper/javabean/model/impl/JavaBeanGenericContextHelper.java
deleted file mode 100644
index a46a4096fb..0000000000
--- a/mapper/javabean/src/main/java/org/hibernate/search/mapper/javabean/model/impl/JavaBeanGenericContextHelper.java
+++ /dev/null
@@ -1,37 +0,0 @@
-/*
- * Hibernate Search, full-text search for your domain model
- *
- * License: GNU Lesser General Public License (LGPL), version 2.1 or later
- * See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>.
- */
-package org.hibernate.search.mapper.javabean.model.impl;
-
-import java.lang.reflect.Type;
-
-import org.hibernate.search.mapper.pojo.model.spi.GenericContextAwarePojoGenericTypeModel;
-import org.hibernate.search.mapper.pojo.model.spi.PojoPropertyModel;
-import org.hibernate.search.mapper.pojo.model.spi.PojoRawTypeModel;
-
-public class JavaBeanGenericContextHelper implements GenericContextAwarePojoGenericTypeModel.Helper {
-	private final JavaBeanBootstrapIntrospector introspector;
-
-	public JavaBeanGenericContextHelper(JavaBeanBootstrapIntrospector introspector) {
-		this.introspector = introspector;
-	}
-
-	@Override
-	public <T> PojoRawTypeModel<T> rawTypeModel(Class<T> clazz) {
-		return introspector.typeModel( clazz );
-	}
-
-	@Override
-	public Object propertyCacheKey(PojoPropertyModel<?> rawPropertyModel) {
-		return rawPropertyModel; // Properties define equals and hashCode as required
-	}
-
-	@Override
-	public Type propertyGenericType(PojoPropertyModel<?> rawPropertyModel) {
-		JavaBeanPropertyModel<?> javaBeanPropertyModel = (JavaBeanPropertyModel<?>) rawPropertyModel;
-		return javaBeanPropertyModel.getGetterGenericReturnType();
-	}
-}
diff --git a/mapper/javabean/src/main/java/org/hibernate/search/mapper/javabean/model/impl/JavaBeanPropertyModel.java b/mapper/javabean/src/main/java/org/hibernate/search/mapper/javabean/model/impl/JavaBeanPropertyModel.java
index fa86d58287..52e1a5052d 100644
--- a/mapper/javabean/src/main/java/org/hibernate/search/mapper/javabean/model/impl/JavaBeanPropertyModel.java
+++ b/mapper/javabean/src/main/java/org/hibernate/search/mapper/javabean/model/impl/JavaBeanPropertyModel.java
@@ -6,114 +6,25 @@
  */
 package org.hibernate.search.mapper.javabean.model.impl;
 
-import java.lang.annotation.Annotation;
-import java.lang.invoke.MethodHandles;
-import java.lang.reflect.Method;
-import java.lang.reflect.Type;
-import java.util.Objects;
-import java.util.stream.Stream;
+import java.lang.reflect.Member;
+import java.util.List;
 
 import org.hibernate.annotations.common.reflection.XProperty;
-import org.hibernate.search.mapper.javabean.log.impl.Log;
-import org.hibernate.search.mapper.pojo.model.hcann.spi.PojoCommonsAnnotationsHelper;
-import org.hibernate.search.mapper.pojo.model.spi.PojoGenericTypeModel;
-import org.hibernate.search.mapper.pojo.model.spi.PojoPropertyModel;
+import org.hibernate.search.mapper.pojo.model.hcann.spi.AbstractPojoHCAnnPropertyModel;
 import org.hibernate.search.util.common.reflect.spi.ValueReadHandle;
-import org.hibernate.search.util.common.logging.impl.LoggerFactory;
 
-class JavaBeanPropertyModel<T> implements PojoPropertyModel<T> {
+class JavaBeanPropertyModel<T> extends AbstractPojoHCAnnPropertyModel<T, JavaBeanBootstrapIntrospector> {
 
-	private static final Log log = LoggerFactory.make( Log.class, MethodHandles.lookup() );
-
-	private final JavaBeanBootstrapIntrospector introspector;
-	private final JavaBeanTypeModel<?> parentTypeModel;
-
-	private final XProperty property;
-	private final Method readMethod;
-
-	private PojoGenericTypeModel<T> typeModel;
-	private ValueReadHandle<T> handle;
-
-	JavaBeanPropertyModel(JavaBeanBootstrapIntrospector introspector, JavaBeanTypeModel<?> parentTypeModel, XProperty property) {
-		this.introspector = introspector;
-		this.parentTypeModel = parentTypeModel;
-		this.property = property;
-		this.readMethod = PojoCommonsAnnotationsHelper.extractUnderlyingMethod( property );
-	}
-
-	/**
-	 * N.B.: equals and hashCode must be defined properly for
-	 * {@link JavaBeanGenericContextHelper#propertyCacheKey(PojoPropertyModel)}
-	 * to work properly.
-	 */
-	@Override
-	public boolean equals(Object o) {
-		if ( this == o ) {
-			return true;
-		}
-		if ( o == null || getClass() != o.getClass() ) {
-			return false;
-		}
-		JavaBeanPropertyModel<?> that = (JavaBeanPropertyModel<?>) o;
-		return Objects.equals( introspector, that.introspector ) &&
-				Objects.equals( parentTypeModel, that.parentTypeModel ) &&
-				Objects.equals( handle(), that.handle() );
-	}
-
-	@Override
-	public int hashCode() {
-		return Objects.hash( introspector, parentTypeModel, handle );
-	}
-
-	@Override
-	public String toString() {
-		return getClass().getSimpleName() + "[" + name() + ", " + getGetterGenericReturnType().getTypeName() + "]";
-	}
-
-	@Override
-	public String name() {
-		return property.getName();
-	}
-
-	@Override
-	public Stream<Annotation> annotations() {
-		return introspector.annotations( property );
-	}
-
-	@Override
-	/*
-	 * The cast is safe as long as both type parameter T and getGetterGenericReturnType
-	 * match the actual type for this property.
-	 */
-	@SuppressWarnings( "unchecked" )
-	public PojoGenericTypeModel<T> typeModel() {
-		if ( typeModel == null ) {
-			try {
-				typeModel = (PojoGenericTypeModel<T>) parentTypeModel.getRawTypeDeclaringContext()
-						.createGenericTypeModel( getGetterGenericReturnType() );
-			}
-			catch (RuntimeException e) {
-				throw log.errorRetrievingPropertyTypeModel( name(), parentTypeModel, e );
-			}
-		}
-		return typeModel;
+	JavaBeanPropertyModel(JavaBeanBootstrapIntrospector introspector,
+			JavaBeanRawTypeModel<?> holderTypeModel,
+			String name, List<XProperty> declaredXProperties,
+			Member member) {
+		super( introspector, holderTypeModel, name, declaredXProperties, member );
 	}
 
 	@Override
 	@SuppressWarnings("unchecked") // By construction, we know the member returns values of type T
-	public ValueReadHandle<T> handle() {
-		if ( handle == null ) {
-			try {
-				handle = (ValueReadHandle<T>) introspector.createValueReadHandle( readMethod );
-			}
-			catch (IllegalAccessException | RuntimeException e) {
-				throw log.errorRetrievingPropertyTypeModel( name(), parentTypeModel, e );
-			}
-		}
-		return handle;
-	}
-
-	Type getGetterGenericReturnType() {
-		return readMethod.getGenericReturnType();
+	protected ValueReadHandle<T> createHandle() throws IllegalAccessException {
+		return (ValueReadHandle<T>) introspector.createValueReadHandle( member );
 	}
 }
diff --git a/mapper/javabean/src/main/java/org/hibernate/search/mapper/javabean/model/impl/JavaBeanRawTypeModel.java b/mapper/javabean/src/main/java/org/hibernate/search/mapper/javabean/model/impl/JavaBeanRawTypeModel.java
new file mode 100644
index 0000000000..8939c253f9
--- /dev/null
+++ b/mapper/javabean/src/main/java/org/hibernate/search/mapper/javabean/model/impl/JavaBeanRawTypeModel.java
@@ -0,0 +1,83 @@
+/*
+ * Hibernate Search, full-text search for your domain model
+ *
+ * License: GNU Lesser General Public License (LGPL), version 2.1 or later
+ * See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>.
+ */
+package org.hibernate.search.mapper.javabean.model.impl;
+
+import java.lang.reflect.Member;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Objects;
+import java.util.function.Function;
+import java.util.stream.Stream;
+
+import org.hibernate.annotations.common.reflection.XProperty;
+import org.hibernate.search.mapper.pojo.model.hcann.spi.AbstractPojoHCAnnRawTypeModel;
+import org.hibernate.search.mapper.pojo.model.spi.GenericContextAwarePojoGenericTypeModel.RawTypeDeclaringContext;
+import org.hibernate.search.mapper.pojo.model.spi.PojoRawTypeIdentifier;
+
+class JavaBeanRawTypeModel<T> extends AbstractPojoHCAnnRawTypeModel<T, JavaBeanBootstrapIntrospector> {
+
+	JavaBeanRawTypeModel(JavaBeanBootstrapIntrospector introspector, PojoRawTypeIdentifier<T> typeIdentifier,
+			RawTypeDeclaringContext<T> rawTypeDeclaringContext) {
+		super( introspector, typeIdentifier, rawTypeDeclaringContext );
+	}
+
+	@Override
+	@SuppressWarnings("unchecked") // xClass represents T, so its supertypes represent ? super T
+	public Stream<JavaBeanRawTypeModel<? super T>> ascendingSuperTypes() {
+		return introspector.ascendingSuperClasses( xClass )
+					.map( xc -> (JavaBeanRawTypeModel<? super T>) introspector.typeModel( xc ) );
+	}
+
+	@Override
+	@SuppressWarnings("unchecked") // xClass represents T, so its supertypes represent ? super T
+	public Stream<JavaBeanRawTypeModel<? super T>> descendingSuperTypes() {
+		return introspector.descendingSuperClasses( xClass )
+				.map( xc -> (JavaBeanRawTypeModel<? super T>) introspector.typeModel( xc ) );
+	}
+
+	@Override
+	protected JavaBeanPropertyModel<?> createPropertyModel(String propertyName) {
+		List<XProperty> declaredXProperties = new ArrayList<>( 2 );
+		XProperty methodAccessXProperty = declaredMethodAccessXPropertiesByName().get( propertyName );
+		if ( methodAccessXProperty != null ) {
+			declaredXProperties.add( methodAccessXProperty );
+		}
+		XProperty fieldAccessXProperty = declaredFieldAccessXPropertiesByName().get( propertyName );
+		if ( fieldAccessXProperty != null ) {
+			declaredXProperties.add( fieldAccessXProperty );
+		}
+
+		Member member = findPropertyMember( propertyName );
+		if ( member == null ) {
+			return null;
+		}
+
+		return new JavaBeanPropertyModel<>(
+				introspector, this, propertyName,
+				declaredXProperties, member
+		);
+	}
+
+	private Member findPropertyMember(String propertyName) {
+		// Try using the getter first (if declared)...
+		Member getter = findInSelfOrParents( t -> t.declaredPropertyGetter( propertyName ) );
+		if ( getter != null ) {
+			return getter;
+		}
+		// ... and fall back to the field (or null if not found)
+		return findInSelfOrParents( t -> t.declaredPropertyField( propertyName ) );
+	}
+
+	private <T2> T2 findInSelfOrParents(Function<JavaBeanRawTypeModel<?>, T2> getter) {
+		return ascendingSuperTypes()
+				.map( getter )
+				.filter( Objects::nonNull )
+				.findFirst()
+				.orElse( null );
+	}
+
+}
diff --git a/mapper/javabean/src/main/java/org/hibernate/search/mapper/javabean/model/impl/JavaBeanTypeModel.java b/mapper/javabean/src/main/java/org/hibernate/search/mapper/javabean/model/impl/JavaBeanTypeModel.java
deleted file mode 100644
index fdf12a15ed..0000000000
--- a/mapper/javabean/src/main/java/org/hibernate/search/mapper/javabean/model/impl/JavaBeanTypeModel.java
+++ /dev/null
@@ -1,141 +0,0 @@
-/*
- * Hibernate Search, full-text search for your domain model
- *
- * License: GNU Lesser General Public License (LGPL), version 2.1 or later
- * See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>.
- */
-package org.hibernate.search.mapper.javabean.model.impl;
-
-import java.lang.annotation.Annotation;
-import java.lang.invoke.MethodHandles;
-import java.lang.reflect.Modifier;
-import java.util.Map;
-import java.util.Objects;
-import java.util.stream.Stream;
-
-import org.hibernate.annotations.common.reflection.XClass;
-import org.hibernate.annotations.common.reflection.XProperty;
-import org.hibernate.search.engine.mapper.model.spi.MappableTypeModel;
-import org.hibernate.search.mapper.javabean.log.impl.Log;
-import org.hibernate.search.mapper.pojo.model.spi.GenericContextAwarePojoGenericTypeModel.RawTypeDeclaringContext;
-import org.hibernate.search.mapper.pojo.model.spi.JavaClassPojoCaster;
-import org.hibernate.search.mapper.pojo.model.spi.PojoCaster;
-import org.hibernate.search.mapper.pojo.model.spi.PojoPropertyModel;
-import org.hibernate.search.mapper.pojo.model.spi.PojoRawTypeModel;
-import org.hibernate.search.mapper.pojo.model.spi.PojoRawTypeIdentifier;
-import org.hibernate.search.util.common.logging.impl.LoggerFactory;
-
-class JavaBeanTypeModel<T> implements PojoRawTypeModel<T> {
-
-	private static final Log log = LoggerFactory.make( Log.class, MethodHandles.lookup() );
-
-	private final JavaBeanBootstrapIntrospector introspector;
-	private final PojoRawTypeIdentifier<T> typeIdentifier;
-	private final RawTypeDeclaringContext<T> rawTypeDeclaringContext;
-	private final PojoCaster<T> caster;
-	private final XClass xClass;
-	private final Map<String, XProperty> declaredProperties;
-
-	JavaBeanTypeModel(JavaBeanBootstrapIntrospector introspector, PojoRawTypeIdentifier<T> typeIdentifier,
-			RawTypeDeclaringContext<T> rawTypeDeclaringContext) {
-		this.introspector = introspector;
-		this.typeIdentifier = typeIdentifier;
-		this.rawTypeDeclaringContext = rawTypeDeclaringContext;
-		this.caster = new JavaClassPojoCaster<>( typeIdentifier.javaClass() );
-		this.xClass = introspector.toXClass( typeIdentifier.javaClass() );
-		this.declaredProperties = introspector.declaredMethodAccessXPropertiesByName( xClass );
-	}
-
-	@Override
-	public boolean equals(Object o) {
-		if ( this == o ) {
-			return true;
-		}
-		if ( o == null || getClass() != o.getClass() ) {
-			return false;
-		}
-		JavaBeanTypeModel<?> that = (JavaBeanTypeModel<?>) o;
-		/*
-		 * We need to take the introspector into account, so that the engine does not confuse
-		 * type models from different mappers during bootstrap.
-		 */
-		return Objects.equals( introspector, that.introspector ) &&
-				Objects.equals( typeIdentifier, that.typeIdentifier );
-	}
-
-	@Override
-	public int hashCode() {
-		return Objects.hash( introspector, typeIdentifier );
-	}
-
-	@Override
-	public String toString() {
-		return getClass().getSimpleName() + "[" + typeIdentifier + "]";
-	}
-
-	@Override
-	public PojoRawTypeIdentifier<T> typeIdentifier() {
-		return typeIdentifier;
-	}
-
-	@Override
-	public String name() {
-		return typeIdentifier.toString();
-	}
-
-	@Override
-	public boolean isAbstract() {
-		return Modifier.isAbstract( typeIdentifier.javaClass().getModifiers() );
-	}
-
-	@Override
-	public boolean isSubTypeOf(MappableTypeModel other) {
-		return other instanceof JavaBeanTypeModel
-				&& ( (JavaBeanTypeModel<?>) other ).typeIdentifier.javaClass().isAssignableFrom( typeIdentifier.javaClass() );
-	}
-
-	@Override
-	@SuppressWarnings("unchecked") // xClass represents T, so its supertypes represent ? super T
-	public Stream<JavaBeanTypeModel<? super T>> ascendingSuperTypes() {
-		return (Stream<JavaBeanTypeModel<? super T>>) introspector.getAscendingSuperTypes( xClass );
-	}
-
-	@Override
-	@SuppressWarnings("unchecked") // xClass represents T, so its supertypes represent ? super T
-	public Stream<? extends PojoRawTypeModel<? super T>> descendingSuperTypes() {
-		return (Stream<? extends PojoRawTypeModel<? super T>>) introspector.getDescendingSuperTypes( xClass );
-	}
-
-	@Override
-	public Stream<Annotation> annotations() {
-		return introspector.annotations( xClass );
-	}
-
-	@Override
-	public PojoPropertyModel<?> property(String propertyName) {
-		return ascendingSuperTypes()
-				.map( model -> model.declaredProperties.get( propertyName ) )
-				.filter( Objects::nonNull )
-				.findFirst().map( this::createProperty )
-				.orElseThrow( () -> log.cannotFindProperty( this, propertyName ) );
-	}
-
-	@Override
-	public Stream<PojoPropertyModel<?>> declaredProperties() {
-		return declaredProperties.values().stream()
-				.map( this::createProperty );
-	}
-
-	@Override
-	public PojoCaster<T> caster() {
-		return caster;
-	}
-
-	RawTypeDeclaringContext<T> getRawTypeDeclaringContext() {
-		return rawTypeDeclaringContext;
-	}
-
-	private PojoPropertyModel<?> createProperty(XProperty property) {
-		return new JavaBeanPropertyModel<>( introspector, this, property );
-	}
-}
