diff --git a/src/backend/executor/execExpr.c b/src/backend/executor/execExpr.c
index db5fcaf..ec896a4 100644
--- a/src/backend/executor/execExpr.c
+++ b/src/backend/executor/execExpr.c
@@ -1364,6 +1364,37 @@ ExecInitExprRec(Expr *node, ExprState *state,
 		case T_ConvertRowtypeExpr:
 			{
 				ConvertRowtypeExpr *convert = (ConvertRowtypeExpr *) node;
+				ConvertRowtypeExpr *tmp_cre = convert;
+				bool		nested_cre = false;
+
+				/*
+				 * If this is a nested ConvertRowtypeExpr resulting from a
+				 * multi-level partition/inheritance hierarchy, its leaf node
+				 * will be a whole-row expression. We can convert the leaf
+				 * whole-row directly into the topmost parent, without
+				 * converting it into the intermediate parent row types.
+				 */
+				while (IsA(tmp_cre->arg, ConvertRowtypeExpr))
+				{
+					tmp_cre = castNode(ConvertRowtypeExpr, tmp_cre->arg);
+					nested_cre = true;
+				}
+
+				if (nested_cre && IsA(tmp_cre->arg, Var) &&
+					castNode(Var, tmp_cre->arg)->varattno == 0)
+				{
+					ConvertRowtypeExpr *new_convert;
+
+					/*
+					 * XXX: Instead of modifying the expression directly, we
+					 * save a modified copy in the execution tree. May be it's
+					 * safe to modify the expression directly, not sure.
+					 */
+					new_convert = makeNode(ConvertRowtypeExpr);
+					memcpy(new_convert, convert, sizeof(ConvertRowtypeExpr));
+					new_convert->arg = tmp_cre->arg;
+					convert = new_convert;
+				}
 
 				/* evaluate argument into step's result area */
 				ExecInitExprRec(convert->arg, state, resv, resnull);
