diff --git a/src/backend/access/common/tupdesc.c b/src/backend/access/common/tupdesc.c
index 5354a04639b..78934c11de1 100644
--- a/src/backend/access/common/tupdesc.c
+++ b/src/backend/access/common/tupdesc.c
@@ -461,6 +461,8 @@ equalTupleDescs(TupleDesc tupdesc1, TupleDesc tupdesc2)
 			return false;
 		if (attr1->attislocal != attr2->attislocal)
 			return false;
+		if (attr1->attishidden != attr2->attishidden)
+			return false;
 		if (attr1->attinhcount != attr2->attinhcount)
 			return false;
 		if (attr1->attcollation != attr2->attcollation)
@@ -641,6 +643,7 @@ TupleDescInitEntry(TupleDesc desc,
 	att->attidentity = '\0';
 	att->attisdropped = false;
 	att->attislocal = true;
+	att->attishidden = false;
 	att->attinhcount = 0;
 	/* attacl, attoptions and attfdwoptions are not present in tupledescs */
 
@@ -700,6 +703,7 @@ TupleDescInitBuiltinEntry(TupleDesc desc,
 	att->attidentity = '\0';
 	att->attisdropped = false;
 	att->attislocal = true;
+	att->attishidden = false;
 	att->attinhcount = 0;
 	/* attacl, attoptions and attfdwoptions are not present in tupledescs */
 
@@ -791,6 +795,7 @@ BuildDescForRelation(List *schema)
 	int32		atttypmod;
 	Oid			attcollation;
 	int			attdim;
+	bool		attishidden;
 
 	/*
 	 * allocate a new tuple descriptor
@@ -843,6 +848,7 @@ BuildDescForRelation(List *schema)
 		att->attnotnull = entry->is_not_null;
 		has_not_null |= entry->is_not_null;
 		att->attislocal = entry->is_local;
+		att->attishidden = false;
 		att->attinhcount = entry->inhcount;
 	}
 
diff --git a/src/backend/bootstrap/bootstrap.c b/src/backend/bootstrap/bootstrap.c
index 8e2cf7df562..acad35de08c 100644
--- a/src/backend/bootstrap/bootstrap.c
+++ b/src/backend/bootstrap/bootstrap.c
@@ -748,6 +748,7 @@ DefineAttr(char *name, char *type, int attnum, int nullness)
 	attrtypes[attnum]->attcacheoff = -1;
 	attrtypes[attnum]->atttypmod = -1;
 	attrtypes[attnum]->attislocal = true;
+	attrtypes[attnum]->attishidden = false;
 
 	if (nullness == BOOTCOL_NULL_FORCE_NOT_NULL)
 	{
diff --git a/src/backend/parser/parse_relation.c b/src/backend/parser/parse_relation.c
index 378cbcbf79e..3c6875e0e0d 100644
--- a/src/backend/parser/parse_relation.c
+++ b/src/backend/parser/parse_relation.c
@@ -2596,6 +2596,13 @@ expandTupleDesc(TupleDesc tupdesc, Alias *eref, int count, int offset,
 			continue;
 		}
 
+		/*
+		 * Skip over hidden fields, unless reproducing a closely matching
+		 * entry (FIXME: check callers whether that's sensible).
+		 */
+		if (attr->attishidden && !include_dropped)
+			continue;
+
 		if (colnames)
 		{
 			char	   *label;
diff --git a/src/backend/parser/parse_target.c b/src/backend/parser/parse_target.c
index b8702d914dc..0e27cd6b100 100644
--- a/src/backend/parser/parse_target.c
+++ b/src/backend/parser/parse_target.c
@@ -1434,7 +1434,7 @@ ExpandRowReference(ParseState *pstate, Node *expr,
 		Form_pg_attribute att = TupleDescAttr(tupleDesc, i);
 		FieldSelect *fselect;
 
-		if (att->attisdropped)
+		if (att->attisdropped || att->attishidden)
 			continue;
 
 		fselect = makeNode(FieldSelect);
diff --git a/src/include/catalog/pg_attribute.h b/src/include/catalog/pg_attribute.h
index 1bac59bf26e..dbad2ebf5be 100644
--- a/src/include/catalog/pg_attribute.h
+++ b/src/include/catalog/pg_attribute.h
@@ -154,6 +154,9 @@ CATALOG(pg_attribute,1249,AttributeRelationId) BKI_BOOTSTRAP BKI_ROWTYPE_OID(75,
 	 */
 	bool		attislocal BKI_DEFAULT(t);
 
+	/* column included in SELECT * expansion */
+	bool		attishidden BKI_DEFAULT(f);
+
 	/* Number of times inherited from direct parent relation(s) */
 	int32		attinhcount BKI_DEFAULT(0);
 
diff --git a/src/include/catalog/pg_class.dat b/src/include/catalog/pg_class.dat
index 5a884a852b5..e6d5e2cdda9 100644
--- a/src/include/catalog/pg_class.dat
+++ b/src/include/catalog/pg_class.dat
@@ -36,7 +36,7 @@
   reloftype => '0', relowner => 'PGUID', relam => '0', relfilenode => '0',
   reltablespace => '0', relpages => '0', reltuples => '0', relallvisible => '0',
   reltoastrelid => '0', relhasindex => 'f', relisshared => 'f',
-  relpersistence => 'p', relkind => 'r', relnatts => '24', relchecks => '0',
+  relpersistence => 'p', relkind => 'r', relnatts => '25', relchecks => '0',
   relhasrules => 'f', relhastriggers => 'f', relhassubclass => 'f',
   relrowsecurity => 'f', relforcerowsecurity => 'f', relispopulated => 't',
   relreplident => 'n', relispartition => 'f', relrewrite => '0',
