diff --git a/src/backend/rewrite/rewriteHandler.c b/src/backend/rewrite/rewriteHandler.c
index d2a0e501d1e..30ae22e43df 100644
--- a/src/backend/rewrite/rewriteHandler.c
+++ b/src/backend/rewrite/rewriteHandler.c
@@ -1859,8 +1859,12 @@ ApplyRetrieveRule(Query *parsetree,
 	rte->rtekind = RTE_SUBQUERY;
 	rte->subquery = rule_action;
 	rte->security_barrier = RelationIsSecurityView(relation);
-	/* Clear fields that should not be set in a subquery RTE */
-	rte->relid = InvalidOid;
+
+	/*
+	 * Clear fields that should not be set in a subquery RTE.  However, we
+	 * retain the relid to support correct operation of makeWholeRowVar during
+	 * planning.
+	 */
 	rte->relkind = 0;
 	rte->rellockmode = 0;
 	rte->tablesample = NULL;
diff --git a/src/include/nodes/parsenodes.h b/src/include/nodes/parsenodes.h
index 6944362c7ac..abc87c59e6f 100644
--- a/src/include/nodes/parsenodes.h
+++ b/src/include/nodes/parsenodes.h
@@ -1017,6 +1017,12 @@ typedef struct RangeTblEntry
 	/*
 	 * Fields valid for a plain relation RTE (else zero):
 	 *
+	 * As a special case, relid can also be set in RTE_SUBQUERY RTEs.  This
+	 * happens when an RTE_RELATION RTE for a view is transformed to an
+	 * RTE_SUBQUERY during rewriting.  We keep the relid because it is useful
+	 * during planning, cf makeWholeRowVar.  (It cannot be relied on during
+	 * execution, because it will not propagate to parallel workers.)
+	 *
 	 * As a special case, RTE_NAMEDTUPLESTORE can also set relid to indicate
 	 * that the tuple format of the tuplestore is the same as the referenced
 	 * relation.  This allows plans referencing AFTER trigger transition
