diff --git a/src/backend/commands/tablecmds.c b/src/backend/commands/tablecmds.c
index 2d4dcd7556..abab55ba00 100644
--- a/src/backend/commands/tablecmds.c
+++ b/src/backend/commands/tablecmds.c
@@ -1753,6 +1753,7 @@ MergeAttributes(List *schema, List *supers, char relpersistence,
 					coldef->raw_default = restdef->raw_default;
 					coldef->cooked_default = restdef->cooked_default;
 					coldef->constraints = restdef->constraints;
+					coldef->identity = restdef->identity;
 					coldef->is_from_type = false;
 					list_delete_cell(schema, rest, prev);
 				}
@@ -2257,6 +2258,7 @@ MergeAttributes(List *schema, List *supers, char relpersistence,
 						coldef->cooked_default = restdef->cooked_default;
 						coldef->constraints = restdef->constraints;
 						coldef->is_from_parent = false;
+						coldef->identity = restdef->identity;
 						list_delete_cell(schema, rest, prev);
 					}
 					else
diff --git a/src/backend/parser/parse_utilcmd.c b/src/backend/parser/parse_utilcmd.c
index 27e568fc62..cbc6f9b466 100644
--- a/src/backend/parser/parse_utilcmd.c
+++ b/src/backend/parser/parse_utilcmd.c
@@ -80,6 +80,7 @@ typedef struct
 	bool		isforeign;		/* true if CREATE/ALTER FOREIGN TABLE */
 	bool		isalter;		/* true if altering existing table */
 	bool		hasoids;		/* does relation have an OID column? */
+	Oid			ofTypeOid;		/* type used with CREATE TABLE OF */
 	List	   *columns;		/* ColumnDef items */
 	List	   *ckconstraints;	/* CHECK constraints */
 	List	   *fkconstraints;	/* FOREIGN KEY constraints */
@@ -231,6 +232,7 @@ transformCreateStmt(CreateStmt *stmt, const char *queryString)
 	cxt.rel = NULL;
 	cxt.inhRelations = stmt->inhRelations;
 	cxt.isalter = false;
+	cxt.ofTypeOid = InvalidOid;
 	cxt.columns = NIL;
 	cxt.ckconstraints = NIL;
 	cxt.fkconstraints = NIL;
@@ -240,6 +242,7 @@ transformCreateStmt(CreateStmt *stmt, const char *queryString)
 	cxt.alist = NIL;
 	cxt.pkey = NULL;
 	cxt.ispartitioned = stmt->partspec != NULL;
+	cxt.partbound = stmt->partbound;
 
 	/*
 	 * Notice that we allow OIDs here only for plain tables, even though
@@ -661,8 +664,84 @@ transformColumnDefinition(CreateStmtContext *cxt, ColumnDef *column)
 				{
 					Type		ctype;
 					Oid			typeOid;
+					TypeName   *typeName;
+					bool		found_type = false;
+					int			i;
 
-					ctype = typenameType(cxt->pstate, column->typeName, NULL);
+					/*
+					 * Look at the type name of the column. When created
+					 * under the context of CREATE TABLE OF, the column type
+					 * name is not specified as part of the column clause, so
+					 * do a lookup at the composite type defined and extract
+					 * the correct type name from it. Columns listed in a
+					 * child partition do not define a type name either, so
+					 * look at the parent partition in this case and extract
+					 * the type needed. Note that the type is needed beforehand
+					 * so as serial evaluations can happen in a consistent way.
+					 */
+					if (OidIsValid(cxt->ofTypeOid))
+					{
+						TupleDesc	tupdesc;
+
+						tupdesc = lookup_rowtype_tupdesc(cxt->ofTypeOid, -1);
+						for (i = 0; i < tupdesc->natts ; i++)
+						{
+							Form_pg_attribute attr = TupleDescAttr(tupdesc, i);
+
+							if (attr->attisdropped)
+								continue;
+
+							if (strcmp(NameStr(attr->attname),
+									   column->colname) == 0)
+							{
+								typeName = makeTypeNameFromOid(attr->atttypid,
+															   attr->atttypmod);
+								found_type = true;
+								break;
+							}
+						}
+						DecrTupleDescRefCount(tupdesc);
+					}
+					else if (cxt->partbound)
+					{
+						Relation	rel;
+						RangeVar   *inh = linitial_node(RangeVar,
+														cxt->inhRelations);
+
+						Assert(list_length(cxt->inhRelations) == 1);
+
+						rel = heap_openrv(inh, AccessShareLock);
+						for (i = 0; i < rel->rd_att->natts; i++)
+						{
+							Form_pg_attribute attr =
+								TupleDescAttr(rel->rd_att, i);
+
+							if (attr->attisdropped)
+								continue;
+							if (strcmp(NameStr(attr->attname),
+									   column->colname) == 0)
+							{
+								typeName = makeTypeNameFromOid(attr->atttypid,
+															   attr->atttypmod);
+								found_type = true;
+								break;
+							}
+						}
+						heap_close(rel, NoLock);
+					}
+					else
+					{
+						typeName = column->typeName;
+						found_type = true;
+					}
+
+					if (!found_type)
+						ereport(ERROR,
+								(errcode(ERRCODE_UNDEFINED_COLUMN),
+								 errmsg("column \"%s\" does not exist",
+										column->colname)));
+
+					ctype = typenameType(cxt->pstate, typeName, NULL);
 					typeOid = HeapTupleGetOid(ctype);
 					ReleaseSysCache(ctype);
 
@@ -1217,6 +1296,7 @@ transformOfType(CreateStmtContext *cxt, TypeName *ofTypename)
 	check_of_type(tuple);
 	ofTypeId = HeapTupleGetOid(tuple);
 	ofTypename->typeOid = ofTypeId; /* cached for later */
+	cxt->ofTypeOid = ofTypeId;
 
 	tupdesc = lookup_rowtype_tupdesc(ofTypeId, -1);
 	for (i = 0; i < tupdesc->natts; i++)
@@ -2686,6 +2766,7 @@ transformAlterTableStmt(Oid relid, AlterTableStmt *stmt,
 	cxt.rel = rel;
 	cxt.inhRelations = NIL;
 	cxt.isalter = true;
+	cxt.ofTypeOid = InvalidOid;
 	cxt.hasoids = false;		/* need not be right */
 	cxt.columns = NIL;
 	cxt.ckconstraints = NIL;
diff --git a/src/test/regress/expected/identity.out b/src/test/regress/expected/identity.out
index 5fa585d6cc..5a6ba61da9 100644
--- a/src/test/regress/expected/identity.out
+++ b/src/test/regress/expected/identity.out
@@ -333,3 +333,38 @@ SELECT * FROM itest8;
 RESET ROLE;
 DROP TABLE itest8;
 DROP USER regress_user1;
+-- typed table
+CREATE TYPE itest_type AS (f1 integer, f2 text, f3 bigint);
+CREATE TABLE itest9 OF itest_type (
+   f4 WITH OPTIONS GENERATED ALWAYS AS IDENTITY); -- error
+ERROR:  column "f4" does not exist
+CREATE TABLE itest9 OF itest_type (
+   f2 WITH OPTIONS GENERATED ALWAYS AS IDENTITY); -- error
+ERROR:  identity column type must be smallint, integer, or bigint
+CREATE TABLE itest9 OF itest_type (
+   f1 WITH OPTIONS GENERATED ALWAYS AS IDENTITY); -- ok
+\d itest9
+                         Table "public.itest9"
+ Column |  Type   | Collation | Nullable |           Default            
+--------+---------+-----------+----------+------------------------------
+ f1     | integer |           | not null | generated always as identity
+ f2     | text    |           |          | 
+ f3     | bigint  |           |          | 
+Typed table of type: itest_type
+
+DROP TYPE itest_type CASCADE;
+NOTICE:  drop cascades to table itest9
+-- partitioned tables
+CREATE TABLE itest_parent (f1 date NOT NULL, f2 int) PARTITION BY RANGE (f1);
+CREATE TABLE itest_child PARTITION OF itest_parent (
+   f2 WITH OPTIONS GENERATED ALWAYS AS IDENTITY
+) FOR VALUES FROM ('2016-07-01') TO ('2016-08-01');
+\d itest_child
+                       Table "public.itest_child"
+ Column |  Type   | Collation | Nullable |           Default            
+--------+---------+-----------+----------+------------------------------
+ f1     | date    |           | not null | 
+ f2     | integer |           | not null | generated always as identity
+Partition of: itest_parent FOR VALUES FROM ('07-01-2016') TO ('08-01-2016')
+
+DROP TABLE itest_parent CASCADE;
diff --git a/src/test/regress/sql/identity.sql b/src/test/regress/sql/identity.sql
index e1b5a074c9..734fac70d0 100644
--- a/src/test/regress/sql/identity.sql
+++ b/src/test/regress/sql/identity.sql
@@ -194,3 +194,22 @@ SELECT * FROM itest8;
 RESET ROLE;
 DROP TABLE itest8;
 DROP USER regress_user1;
+
+-- typed table
+CREATE TYPE itest_type AS (f1 integer, f2 text, f3 bigint);
+CREATE TABLE itest9 OF itest_type (
+   f4 WITH OPTIONS GENERATED ALWAYS AS IDENTITY); -- error
+CREATE TABLE itest9 OF itest_type (
+   f2 WITH OPTIONS GENERATED ALWAYS AS IDENTITY); -- error
+CREATE TABLE itest9 OF itest_type (
+   f1 WITH OPTIONS GENERATED ALWAYS AS IDENTITY); -- ok
+\d itest9
+DROP TYPE itest_type CASCADE;
+
+-- partitioned tables
+CREATE TABLE itest_parent (f1 date NOT NULL, f2 int) PARTITION BY RANGE (f1);
+CREATE TABLE itest_child PARTITION OF itest_parent (
+   f2 WITH OPTIONS GENERATED ALWAYS AS IDENTITY
+) FOR VALUES FROM ('2016-07-01') TO ('2016-08-01');
+\d itest_child
+DROP TABLE itest_parent CASCADE;
