diff --git a/bson/src/main/org/bson/codecs/pojo/PojoBuilderHelper.java b/bson/src/main/org/bson/codecs/pojo/PojoBuilderHelper.java
index a1b55290ac0..9bcce174380 100644
--- a/bson/src/main/org/bson/codecs/pojo/PojoBuilderHelper.java
+++ b/bson/src/main/org/bson/codecs/pojo/PojoBuilderHelper.java
@@ -25,6 +25,7 @@
 import java.lang.reflect.TypeVariable;
 import java.util.ArrayList;
 import java.util.HashMap;
+import java.util.LinkedHashSet;
 import java.util.List;
 import java.util.Map;
 import java.util.Set;
@@ -50,12 +51,12 @@ static <T> void configureClassModelBuilder(final ClassModelBuilder<T> classModel
         ArrayList<Annotation> annotations = new ArrayList<Annotation>();
         Set<String> propertyNames = new TreeSet<String>();
         Map<String, TypeParameterMap> propertyTypeParameterMap = new HashMap<String, TypeParameterMap>();
-        Class<? super T> currentClass = clazz;
         String declaringClassName =  clazz.getSimpleName();
-        TypeData<?> parentClassTypeData = null;
 
         Map<String, PropertyMetadata<?>> propertyNameMap = new HashMap<String, PropertyMetadata<?>>();
-        while (!currentClass.isEnum() && currentClass.getSuperclass() != null) {
+        for (ClassWithParentTypeData<? super T> currentClassWithParentTypeData : getClassHierarchy(clazz, null)) {
+            Class<? super T> currentClass = currentClassWithParentTypeData.clazz;
+            TypeData<?> parentClassTypeData = currentClassWithParentTypeData.parentClassTypeData;
             annotations.addAll(asList(currentClass.getDeclaredAnnotations()));
             List<String> genericTypeNames = new ArrayList<String>();
             for (TypeVariable<? extends Class<? super T>> classTypeVariable : currentClass.getTypeParameters()) {
@@ -116,13 +117,6 @@ static <T> void configureClassModelBuilder(final ClassModelBuilder<T> classModel
                     }
                 }
             }
-
-            parentClassTypeData = TypeData.newInstance(currentClass.getGenericSuperclass(), currentClass);
-            currentClass = currentClass.getSuperclass();
-        }
-
-        if (currentClass.isInterface()) {
-            annotations.addAll(asList(currentClass.getDeclaredAnnotations()));
         }
 
         for (String propertyName : propertyNames) {
@@ -261,6 +255,33 @@ static <V> V stateNotNull(final String property, final V value) {
         return value;
     }
 
+    @SuppressWarnings("unchecked")
+    private static <T> Set<ClassWithParentTypeData<? super T>> getClassHierarchy(final Class<? super T> clazz,
+                                                                                 final TypeData<?> classTypeData) {
+        Set<ClassWithParentTypeData<? super T>> classesToScan = new LinkedHashSet<>();
+        Class<? super T> currentClass = clazz;
+        TypeData<?> parentClassTypeData = classTypeData;
+        while (currentClass != null && !currentClass.isEnum() && !currentClass.equals(Object.class)) {
+            classesToScan.add(new ClassWithParentTypeData<>(currentClass, parentClassTypeData));
+            parentClassTypeData = TypeData.newInstance(currentClass.getGenericSuperclass(), currentClass);
+            for (Class<?> interfaceClass : currentClass.getInterfaces()) {
+                classesToScan.addAll(getClassHierarchy((Class<? super T>) interfaceClass, parentClassTypeData));
+            }
+            currentClass = currentClass.getSuperclass();
+        }
+        return classesToScan;
+    }
+
+    private static final class ClassWithParentTypeData<T> {
+        private final Class<T> clazz;
+        private final TypeData<?> parentClassTypeData;
+
+        private ClassWithParentTypeData(final Class<T> clazz, final TypeData<?> parentClassTypeData) {
+            this.clazz = clazz;
+            this.parentClassTypeData = parentClassTypeData;
+        }
+    }
+
     private PojoBuilderHelper() {
     }
 }
diff --git a/bson/src/test/unit/org/bson/codecs/pojo/PojoCustomTest.java b/bson/src/test/unit/org/bson/codecs/pojo/PojoCustomTest.java
index 1d9213a0c81..5b38b7e7529 100644
--- a/bson/src/test/unit/org/bson/codecs/pojo/PojoCustomTest.java
+++ b/bson/src/test/unit/org/bson/codecs/pojo/PojoCustomTest.java
@@ -30,6 +30,7 @@
 import org.bson.codecs.pojo.entities.AsymmetricalCreatorModel;
 import org.bson.codecs.pojo.entities.AsymmetricalIgnoreModel;
 import org.bson.codecs.pojo.entities.AsymmetricalModel;
+import org.bson.codecs.pojo.entities.ComposeInterfaceModel;
 import org.bson.codecs.pojo.entities.ConcreteAndNestedAbstractInterfaceModel;
 import org.bson.codecs.pojo.entities.ConcreteCollectionsModel;
 import org.bson.codecs.pojo.entities.ConcreteStandAloneAbstractInterfaceModel;
@@ -39,6 +40,8 @@
 import org.bson.codecs.pojo.entities.CustomPropertyCodecOptionalModel;
 import org.bson.codecs.pojo.entities.GenericTreeModel;
 import org.bson.codecs.pojo.entities.InterfaceBasedModel;
+import org.bson.codecs.pojo.entities.InterfaceModelB;
+import org.bson.codecs.pojo.entities.InterfaceModelImpl;
 import org.bson.codecs.pojo.entities.InvalidCollectionModel;
 import org.bson.codecs.pojo.entities.InvalidGetterAndSetterModel;
 import org.bson.codecs.pojo.entities.InvalidMapModel;
@@ -65,6 +68,7 @@
 import org.bson.codecs.pojo.entities.conventions.CreatorConstructorPrimitivesModel;
 import org.bson.codecs.pojo.entities.conventions.CreatorConstructorThrowsExceptionModel;
 import org.bson.codecs.pojo.entities.conventions.CreatorMethodThrowsExceptionModel;
+import org.bson.codecs.pojo.entities.conventions.InterfaceModelBInstanceCreatorConvention;
 import org.bson.codecs.pojo.entities.conventions.MapGetterImmutableModel;
 import org.bson.codecs.pojo.entities.conventions.MapGetterMutableModel;
 import org.bson.codecs.pojo.entities.conventions.MapGetterNonEmptyModel;
@@ -499,7 +503,7 @@ public void testDecodingInvalidMapModel() {
     public void testEncodingInvalidCollectionModel() {
         try {
             encodesTo(getPojoCodecProviderBuilder(InvalidCollectionModel.class), new InvalidCollectionModel(asList(1, 2, 3)),
-                "{collectionField: [1, 2, 3]}");
+                    "{collectionField: [1, 2, 3]}");
         } catch (CodecConfigurationException e) {
             assertTrue(e.getMessage().startsWith("Failed to encode 'InvalidCollectionModel'. Encoding 'collectionField' errored with:"));
             throw e;
@@ -512,6 +516,17 @@ public void testInvalidMapModelWithCustomPropertyCodecProvider() {
                 "{'invalidMap': {'1': 1, '2': 2}}");
     }
 
+    @Test
+    public void testInterfaceModelCreatorMadeInConvention() {
+        roundTrip(
+                getPojoCodecProviderBuilder(ComposeInterfaceModel.class, InterfaceModelB.class, InterfaceModelImpl.class)
+                        .conventions(Collections.singletonList(new InterfaceModelBInstanceCreatorConvention())),
+                new ComposeInterfaceModel("someTitle",
+                        new InterfaceModelImpl("a", "b")),
+                "{'title': 'someTitle', 'nestedModel': {'propertyA': 'a', 'propertyB': 'b'}}"
+        );
+    }
+
     @Test(expected = CodecConfigurationException.class)
     public void testConstructorNotPublicModel() {
         decodingShouldFail(getCodec(ConstructorNotPublicModel.class), "{'integerField': 99}");
diff --git a/bson/src/test/unit/org/bson/codecs/pojo/entities/ComposeInterfaceModel.java b/bson/src/test/unit/org/bson/codecs/pojo/entities/ComposeInterfaceModel.java
new file mode 100644
index 00000000000..b2d7beb765d
--- /dev/null
+++ b/bson/src/test/unit/org/bson/codecs/pojo/entities/ComposeInterfaceModel.java
@@ -0,0 +1,74 @@
+/*
+ * Copyright 2008-present MongoDB, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.bson.codecs.pojo.entities;
+
+import java.util.Objects;
+
+public class ComposeInterfaceModel {
+    private String title;
+    private InterfaceModelB nestedModel;
+
+    public ComposeInterfaceModel() {
+    }
+
+    public ComposeInterfaceModel(final String title, final InterfaceModelB nestedModel) {
+        this.title = title;
+        this.nestedModel = nestedModel;
+    }
+
+    public String getTitle() {
+        return title;
+    }
+
+    public void setTitle(final String title) {
+        this.title = title;
+    }
+
+    public InterfaceModelB getNestedModel() {
+        return nestedModel;
+    }
+
+    public void setNestedModel(final InterfaceModelB nestedModel) {
+        this.nestedModel = nestedModel;
+    }
+
+    @Override
+    public boolean equals(final Object o) {
+        if (this == o) {
+            return true;
+        }
+        if (o == null || getClass() != o.getClass()) {
+            return false;
+        }
+        ComposeInterfaceModel that = (ComposeInterfaceModel) o;
+        return Objects.equals(title, that.title)
+                && Objects.equals(nestedModel, that.nestedModel);
+    }
+
+    @Override
+    public int hashCode() {
+        return Objects.hash(title, nestedModel);
+    }
+
+    @Override
+    public String toString() {
+        return "ComposeInterfaceModel{"
+                + "title='" + title + '\''
+                + ", nestedModel=" + nestedModel
+                + '}';
+    }
+}
diff --git a/bson/src/test/unit/org/bson/codecs/pojo/entities/InterfaceModelImpl.java b/bson/src/test/unit/org/bson/codecs/pojo/entities/InterfaceModelImpl.java
index 90828dc8e6e..9db110c6115 100644
--- a/bson/src/test/unit/org/bson/codecs/pojo/entities/InterfaceModelImpl.java
+++ b/bson/src/test/unit/org/bson/codecs/pojo/entities/InterfaceModelImpl.java
@@ -63,7 +63,15 @@ public boolean equals(final Object o) {
     @Override
     public int hashCode() {
         int result = getPropertyA() != null ? getPropertyA().hashCode() : 0;
-        result = 31 * result + getPropertyB() != null ? getPropertyB().hashCode() : 0;
+        result = 31 * result + (getPropertyB() != null ? getPropertyB().hashCode() : 0);
         return result;
     }
+
+    @Override
+    public String toString() {
+        return "InterfaceModelImpl{"
+                + "propertyA='" + getPropertyA() + "', "
+                + "propertyB='" + getPropertyB() + '\''
+                + '}';
+    }
 }
diff --git a/bson/src/test/unit/org/bson/codecs/pojo/entities/conventions/InterfaceModelBInstanceCreatorConvention.java b/bson/src/test/unit/org/bson/codecs/pojo/entities/conventions/InterfaceModelBInstanceCreatorConvention.java
new file mode 100644
index 00000000000..88781c40513
--- /dev/null
+++ b/bson/src/test/unit/org/bson/codecs/pojo/entities/conventions/InterfaceModelBInstanceCreatorConvention.java
@@ -0,0 +1,54 @@
+/*
+ * Copyright 2008-present MongoDB, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.bson.codecs.pojo.entities.conventions;
+
+import org.bson.codecs.pojo.ClassModelBuilder;
+import org.bson.codecs.pojo.Convention;
+import org.bson.codecs.pojo.InstanceCreator;
+import org.bson.codecs.pojo.PropertyModel;
+import org.bson.codecs.pojo.entities.InterfaceModelB;
+import org.bson.codecs.pojo.entities.InterfaceModelImpl;
+
+public class InterfaceModelBInstanceCreatorConvention implements Convention {
+    @Override
+    @SuppressWarnings("unchecked")
+    public void apply(final ClassModelBuilder<?> classModelBuilder) {
+        if (classModelBuilder.getType().equals(InterfaceModelB.class)) {
+            // Simulate a custom implementation of InstanceCreator factory
+            // (This one can be generated automatically, but, a real use case can have an advanced reflection based
+            // solution that the POJO Codec doesn't support out of the box)
+            ((ClassModelBuilder<InterfaceModelB>) classModelBuilder).instanceCreatorFactory(() -> {
+                InterfaceModelB interfaceModelB = new InterfaceModelImpl();
+                return new InstanceCreator<InterfaceModelB>() {
+                    @Override
+                    public <S> void set(final S value, final PropertyModel<S> propertyModel) {
+                        if (propertyModel.getName().equals("propertyA")) {
+                            interfaceModelB.setPropertyA((String) value);
+                        } else if (propertyModel.getName().equals("propertyB")) {
+                            interfaceModelB.setPropertyB((String) value);
+                        }
+                    }
+
+                    @Override
+                    public InterfaceModelB getInstance() {
+                        return interfaceModelB;
+                    }
+                };
+            });
+        }
+    }
+}