diff --git a/cayenne-server/src/main/java/org/apache/cayenne/BaseContext.java b/cayenne-server/src/main/java/org/apache/cayenne/BaseContext.java
index 981db73c77..3a2db3a577 100644
--- a/cayenne-server/src/main/java/org/apache/cayenne/BaseContext.java
+++ b/cayenne-server/src/main/java/org/apache/cayenne/BaseContext.java
@@ -637,7 +637,7 @@ protected void injectInitialValue(Object obj) {
 
 		ObjEntity entity;
 		try {
-			entity = getEntityResolver().getObjEntity(object.getClass());
+			entity = getEntityResolver().getObjEntity(object);
 		} catch (CayenneRuntimeException ex) {
 			// ObjEntity cannot be fetched, ignored
 			entity = null;
diff --git a/cayenne-server/src/main/java/org/apache/cayenne/reflect/ClassDescriptor.java b/cayenne-server/src/main/java/org/apache/cayenne/reflect/ClassDescriptor.java
index 392e739237..31e485f582 100644
--- a/cayenne-server/src/main/java/org/apache/cayenne/reflect/ClassDescriptor.java
+++ b/cayenne-server/src/main/java/org/apache/cayenne/reflect/ClassDescriptor.java
@@ -87,14 +87,14 @@ public interface ClassDescriptor {
     ClassDescriptor getSuperclassDescriptor();
 
     /**
-     * Returns the most "specialized" descriptor for a given class. This method assumes
+     * Returns the most "specialized" descriptor for a given ObjEntity. This method assumes
      * that the following is true:
-     * 
+     *
      * <pre>
-     * this.getObjectClass().isAssignableFrom(objectClass)
+     * this.getObjectClass().isAssignableFrom(subEntity.getJavaClass())
      * </pre>
      */
-    ClassDescriptor getSubclassDescriptor(Class<?> objectClass);
+    ClassDescriptor getSubclassDescriptor(ObjEntity subEntity);
 
     /**
      * Creates a new instance of a class described by this object.
diff --git a/cayenne-server/src/main/java/org/apache/cayenne/reflect/LazyClassDescriptorDecorator.java b/cayenne-server/src/main/java/org/apache/cayenne/reflect/LazyClassDescriptorDecorator.java
index 821334e8a6..1f08faba78 100644
--- a/cayenne-server/src/main/java/org/apache/cayenne/reflect/LazyClassDescriptorDecorator.java
+++ b/cayenne-server/src/main/java/org/apache/cayenne/reflect/LazyClassDescriptorDecorator.java
@@ -146,9 +146,9 @@ public PropertyDescriptor getProperty(String propertyName) {
         return descriptor.getProperty(propertyName);
     }
 
-    public ClassDescriptor getSubclassDescriptor(Class<?> objectClass) {
+    public ClassDescriptor getSubclassDescriptor(ObjEntity subEntity) {
         checkDescriptorInitialized();
-        return descriptor.getSubclassDescriptor(objectClass);
+        return descriptor.getSubclassDescriptor(subEntity);
     }
 
     public ClassDescriptor getSuperclassDescriptor() {
diff --git a/cayenne-server/src/main/java/org/apache/cayenne/reflect/PersistentDescriptor.java b/cayenne-server/src/main/java/org/apache/cayenne/reflect/PersistentDescriptor.java
index 24d83aee88..dcb691afd4 100644
--- a/cayenne-server/src/main/java/org/apache/cayenne/reflect/PersistentDescriptor.java
+++ b/cayenne-server/src/main/java/org/apache/cayenne/reflect/PersistentDescriptor.java
@@ -209,16 +209,16 @@ public void removeDeclaredProperty(String propertyName) {
 	}
 
 	/**
-	 * Adds a subclass descriptor that maps to a given class name.
+	 * Adds a subclass descriptor that maps to a given entity name.
 	 */
-	public void addSubclassDescriptor(String className, ClassDescriptor subclassDescriptor) {
+	public void addSubclassDescriptor(String entityName, ClassDescriptor subclassDescriptor) {
 		// note that 'className' should be used instead of
 		// "subclassDescriptor.getEntity().getClassName()", as this method is
 		// called in
 		// the early phases of descriptor initialization and we do not want to
 		// trigger
 		// subclassDescriptor resolution just yet to prevent stack overflow.
-		subclassDescriptors.put(className, subclassDescriptor);
+		subclassDescriptors.put(entityName, subclassDescriptor);
 	}
 
 	public ObjEntity getEntity() {
@@ -257,23 +257,26 @@ void setObjectClass(Class<?> objectClass) {
 		this.objectClass = objectClass;
 	}
 
-	public ClassDescriptor getSubclassDescriptor(Class<?> objectClass) {
-		if (objectClass == null) {
-			throw new IllegalArgumentException("Null objectClass");
+	public ClassDescriptor getSubclassDescriptor(ObjEntity subEntity) {
+		if (subEntity == null) {
+			throw new IllegalArgumentException("Null subEntity");
 		}
 
 		if (subclassDescriptors.isEmpty()) {
 			return this;
 		}
 
-		ClassDescriptor subclassDescriptor = subclassDescriptors.get(objectClass.getName());
+		ClassDescriptor subclassDescriptor = subclassDescriptors.get(subEntity.getName());
 
 		// ascend via the class hierarchy (only doing it if there are multiple
 		// choices)
 		if (subclassDescriptor == null) {
-			Class<?> currentClass = objectClass;
-			while (subclassDescriptor == null && (currentClass = currentClass.getSuperclass()) != null) {
-				subclassDescriptor = subclassDescriptors.get(currentClass.getName());
+			ObjEntity currentEntity = subEntity;
+			while (subclassDescriptor == null && (currentEntity = currentEntity.getSuperEntity()) != null) {
+				if(currentEntity == null){
+					break;
+				}
+				subclassDescriptor = subclassDescriptors.get(currentEntity.getName());
 			}
 		}
 
diff --git a/cayenne-server/src/main/java/org/apache/cayenne/reflect/PersistentDescriptorFactory.java b/cayenne-server/src/main/java/org/apache/cayenne/reflect/PersistentDescriptorFactory.java
index 68f3f7a4db..2c2d74ef26 100644
--- a/cayenne-server/src/main/java/org/apache/cayenne/reflect/PersistentDescriptorFactory.java
+++ b/cayenne-server/src/main/java/org/apache/cayenne/reflect/PersistentDescriptorFactory.java
@@ -173,7 +173,7 @@ protected void indexSubclassDescriptors(PersistentDescriptor descriptor, EntityI
 
             for (EntityInheritanceTree child : inheritanceTree.getChildren()) {
                 ObjEntity childEntity = child.getEntity();
-                descriptor.addSubclassDescriptor(childEntity.getClassName(),
+                descriptor.addSubclassDescriptor(childEntity.getName(),
                         descriptorMap.getDescriptor(childEntity.getName()));
 
                 indexSubclassDescriptors(descriptor, child);
diff --git a/cayenne-server/src/main/java/org/apache/cayenne/util/DeepMergeOperation.java b/cayenne-server/src/main/java/org/apache/cayenne/util/DeepMergeOperation.java
index fe5c781ac9..e14d74ea5c 100644
--- a/cayenne-server/src/main/java/org/apache/cayenne/util/DeepMergeOperation.java
+++ b/cayenne-server/src/main/java/org/apache/cayenne/util/DeepMergeOperation.java
@@ -81,7 +81,7 @@ private <T extends Persistent> T merge(
         final T target = shallowMergeOperation.merge(peerInParentContext);
         seen.put(id, target);
 
-        descriptor = descriptor.getSubclassDescriptor(peerInParentContext.getClass());
+        descriptor = descriptor.getSubclassDescriptor(entityResolver.getObjEntity(id.getEntityName()));
         descriptor.visitProperties(new PropertyVisitor() {
 
             public boolean visitToOne(ToOneProperty property) {
diff --git a/cayenne-server/src/main/java/org/apache/cayenne/util/ObjectDetachOperation.java b/cayenne-server/src/main/java/org/apache/cayenne/util/ObjectDetachOperation.java
index f5a70641fd..0091c07c4f 100644
--- a/cayenne-server/src/main/java/org/apache/cayenne/util/ObjectDetachOperation.java
+++ b/cayenne-server/src/main/java/org/apache/cayenne/util/ObjectDetachOperation.java
@@ -19,6 +19,7 @@
 
 package org.apache.cayenne.util;
 
+import org.apache.cayenne.Cayenne;
 import org.apache.cayenne.CayenneRuntimeException;
 import org.apache.cayenne.ObjectId;
 import org.apache.cayenne.Persistent;
@@ -86,7 +87,7 @@ public Object detach(
             return seenTarget;
         }
 
-        descriptor = descriptor.getSubclassDescriptor(source.getClass());
+        descriptor = descriptor.getSubclassDescriptor(Cayenne.getObjEntity(source));
 
         // presumably id's entity name should be of the right subclass.
         final ClassDescriptor targetDescriptor = targetResolver.getClassDescriptor(id
diff --git a/cayenne-server/src/test/java/org/apache/cayenne/access/VerticalInheritanceIT.java b/cayenne-server/src/test/java/org/apache/cayenne/access/VerticalInheritanceIT.java
index 1b49875a4d..26c5d41579 100644
--- a/cayenne-server/src/test/java/org/apache/cayenne/access/VerticalInheritanceIT.java
+++ b/cayenne-server/src/test/java/org/apache/cayenne/access/VerticalInheritanceIT.java
@@ -18,6 +18,7 @@
  ****************************************************************/
 package org.apache.cayenne.access;
 
+import java.lang.reflect.Field;
 import java.sql.SQLException;
 import java.sql.Types;
 import java.util.Collections;
@@ -25,6 +26,7 @@
 import java.util.List;
 import java.util.Map;
 
+import org.apache.cayenne.DataObject;
 import org.apache.cayenne.ObjectContext;
 import org.apache.cayenne.configuration.server.ServerRuntime;
 import org.apache.cayenne.di.Inject;
@@ -32,6 +34,9 @@
 import org.apache.cayenne.query.ObjectSelect;
 import org.apache.cayenne.query.SelectById;
 import org.apache.cayenne.query.SelectQuery;
+import org.apache.cayenne.reflect.ClassDescriptor;
+import org.apache.cayenne.reflect.LazyClassDescriptorDecorator;
+import org.apache.cayenne.reflect.PersistentDescriptor;
 import org.apache.cayenne.test.jdbc.DBHelper;
 import org.apache.cayenne.test.jdbc.TableHelper;
 import org.apache.cayenne.testdo.inheritance_vertical.Iv1Root;
@@ -755,4 +760,48 @@ public void testCountEjbqlQuery() throws Exception {
 		EJBQLQuery query3 = new EJBQLQuery("SELECT COUNT(a) FROM IvSub2 a");
 		assertEquals(Collections.singletonList(2L), context.performQuery(query3));
 	}
+
+	@Test
+	public void testGenericVerticalInheritancePersistentDescriptor() throws NoSuchFieldException, IllegalAccessException {
+		final LazyClassDescriptorDecorator lazyStudentDescriptor = (LazyClassDescriptorDecorator) context.getEntityResolver().getClassDescriptor("GenStudent");
+		final ClassDescriptor studentDescriptor = lazyStudentDescriptor.getDescriptor();
+
+		final Field subclassDescriptorsField = PersistentDescriptor.class.getDeclaredField("subclassDescriptors");
+		subclassDescriptorsField.setAccessible(true);
+		final Map<String, ClassDescriptor> subclassDescriptors = (Map<String, ClassDescriptor>) subclassDescriptorsField.get(studentDescriptor);
+		assertEquals(2, subclassDescriptors.size());
+	}
+
+	@Test
+	public void testInsertTwoGenericVerticalInheritanceObjects() {
+		// Generic DataObjects play nicer with a DataContext
+		final DataContext dataContext = (DataContext) context;
+
+		final DataObject girlEmma = (DataObject) dataContext.newObject("GenGirl");
+		final DataObject boyLuke = (DataObject) dataContext.newObject("GenBoy");
+
+		assertEquals("Girl is type G", girlEmma.readProperty("type"), "G");
+		assertEquals("Boy is type B", boyLuke.readProperty("type"), "B");
+
+		girlEmma.writeProperty("reference", "g1");
+		girlEmma.writeProperty("name", "Emma");
+		girlEmma.writeProperty("toyDolls", 5);
+
+		boyLuke.writeProperty("reference", "b1");
+		boyLuke.writeProperty("name", "Luke");
+		boyLuke.writeProperty("toyTrucks", 12);
+
+		context.commitChanges();
+
+		assertEquals(2, ObjectSelect.query(DataObject.class, "GenStudent").selectCount(context));
+
+		final List<DataObject> students = ObjectSelect.query(DataObject.class, "GenStudent").select(context);
+		assertTrue(students.contains(girlEmma));
+		assertTrue(students.contains(boyLuke));
+
+		final List<DataObject> girls = ObjectSelect.query(DataObject.class, "GenGirl").select(context);
+		assertEquals(1, girls.size());
+		final List<DataObject> boys = ObjectSelect.query(DataObject.class, "GenBoy").select(context);
+		assertEquals(1, boys.size());
+	}
 }
diff --git a/cayenne-server/src/test/resources/inheritance-vertical.map.xml b/cayenne-server/src/test/resources/inheritance-vertical.map.xml
index 25b772a912..782c8ea083 100644
--- a/cayenne-server/src/test/resources/inheritance-vertical.map.xml
+++ b/cayenne-server/src/test/resources/inheritance-vertical.map.xml
@@ -81,6 +81,20 @@
 		<db-attribute name="ID" type="INTEGER" isPrimaryKey="true" isMandatory="true"/>
 		<db-attribute name="IV_ROOT_ID" type="INTEGER" isMandatory="true"/>
 	</db-entity>
+	<db-entity name="GEN_STUDENT">
+		<db-attribute name="ID" type="INTEGER" isPrimaryKey="true" isMandatory="true"/>
+		<db-attribute name="NAME" type="VARCHAR" isMandatory="true" length="50"/>
+		<db-attribute name="REFERENCE" type="VARCHAR" isMandatory="true" length="10"/>
+		<db-attribute name="TYPE" type="CHAR" isMandatory="true" length="1"/>
+	</db-entity>
+	<db-entity name="GEN_BOY">
+		<db-attribute name="ID" type="INTEGER" isPrimaryKey="true" isMandatory="true"/>
+		<db-attribute name="TOY_TRUCKS" type="SMALLINT" length="4"/>
+	</db-entity>
+	<db-entity name="GEN_GIRL">
+		<db-attribute name="ID" type="INTEGER" isPrimaryKey="true" isMandatory="true"/>
+		<db-attribute name="TOY_DOLLS" type="SMALLINT" length="4"/>
+	</db-entity>
 	<obj-entity name="Iv1Root" className="org.apache.cayenne.testdo.inheritance_vertical.Iv1Root" dbEntityName="IV1_ROOT">
 		<obj-attribute name="discriminator" type="java.lang.String" db-attribute-path="DISCRIMINATOR"/>
 		<obj-attribute name="name" type="java.lang.String" db-attribute-path="NAME"/>
@@ -149,6 +163,19 @@
 		<qualifier><![CDATA[discriminator = "IvSub3"]]></qualifier>
 		<pre-persist method-name="onPrePersist"/>
 	</obj-entity>
+	<obj-entity name="GenStudent" abstract="true" dbEntityName="GEN_STUDENT">
+		<obj-attribute name="name" type="java.lang.String" db-attribute-path="NAME"/>
+		<obj-attribute name="reference" type="java.lang.String" db-attribute-path="REFERENCE"/>
+		<obj-attribute name="type" type="java.lang.String" db-attribute-path="TYPE"/>
+	</obj-entity>
+	<obj-entity name="GenBoy" superEntityName="GenStudent">
+		<qualifier><![CDATA[type = "B"]]></qualifier>
+		<obj-attribute name="toyTrucks" type="java.lang.Short" db-attribute-path="boy.TOY_TRUCKS"/>
+	</obj-entity>
+	<obj-entity name="GenGirl" superEntityName="GenStudent">
+		<qualifier><![CDATA[type = "G"]]></qualifier>
+		<obj-attribute name="toyDolls" type="java.lang.Short" db-attribute-path="girl.TOY_DOLLS"/>
+	</obj-entity>
 	<db-relationship name="sub1" source="IV1_ROOT" target="IV1_SUB1" toDependentPK="true">
 		<db-attribute-pair source="ID" target="ID"/>
 	</db-relationship>
@@ -233,6 +260,18 @@
 	<db-relationship name="ivRoot1" source="IV_SUB3" target="IV_ROOT">
 		<db-attribute-pair source="IV_ROOT_ID" target="ID"/>
 	</db-relationship>
+	<db-relationship name="student" source="GEN_BOY" target="GEN_STUDENT">
+		<db-attribute-pair source="ID" target="ID"/>
+	</db-relationship>
+	<db-relationship name="student" source="GEN_GIRL" target="GEN_STUDENT">
+		<db-attribute-pair source="ID" target="ID"/>
+	</db-relationship>
+	<db-relationship name="boy" source="GEN_STUDENT" target="GEN_BOY" toDependentPK="true">
+		<db-attribute-pair source="ID" target="ID"/>
+	</db-relationship>
+	<db-relationship name="girl" source="GEN_STUDENT" target="GEN_GIRL" toDependentPK="true">
+		<db-attribute-pair source="ID" target="ID"/>
+	</db-relationship>
 	<obj-relationship name="x" source="Iv2Sub1" target="Iv2X" deleteRule="Nullify" db-relationship-path="sub1.x"/>
 	<obj-relationship name="children" source="IvConcrete" target="IvConcrete" deleteRule="Deny" db-relationship-path="children"/>
 	<obj-relationship name="parent" source="IvConcrete" target="IvConcrete" deleteRule="Nullify" db-relationship-path="parent"/>