diff --git a/src/backend/utils/cache/relcache.c b/src/backend/utils/cache/relcache.c
index feca620cff..a25ead01d4 100644
--- a/src/backend/utils/cache/relcache.c
+++ b/src/backend/utils/cache/relcache.c
@@ -1202,6 +1202,9 @@ RelationBuildDesc(Oid targetRelId, bool insertIt)
 		relation->rd_pdcxt = NULL;
 	}
 
+	relation->rd_partdesc_orig = NULL;
+	relation->rd_pdcxt_orig = NULL;
+
 	/*
 	 * if it's an index, initialize index-related information
 	 */
@@ -2012,6 +2015,20 @@ RelationClose(Relation relation)
 	/* Note: no locking manipulations needed */
 	RelationDecrementReferenceCount(relation);
 
+	/*
+	 * If the partdesc has been changed while the relation had a non-zero
+	 * ref count we'll have stored the original partdesc.  When the ref
+	 * count reaches 0 we must get rid of the original partdesc and destroy
+	 * the memory context it was stored in.
+	 */
+	if (relation->rd_partdesc_orig &&
+		RelationHasReferenceCountZero(relation))
+	{
+		MemoryContextDelete(relation->rd_pdcxt_orig);
+		relation->rd_partdesc_orig = NULL;
+		relation->rd_pdcxt_orig = NULL;
+	}
+
 #ifdef RELCACHE_FORCE_RELEASE
 	if (RelationHasReferenceCountZero(relation) &&
 		relation->rd_createSubid == InvalidSubTransactionId &&
@@ -2288,7 +2305,7 @@ RelationDestroyRelation(Relation relation, bool remember_tupdesc)
 		MemoryContextDelete(relation->rd_rsdesc->rscxt);
 	if (relation->rd_partkeycxt)
 		MemoryContextDelete(relation->rd_partkeycxt);
-	if (relation->rd_pdcxt)
+	if (relation->rd_pdcxt && !relation->rd_pdcxt_orig)
 		MemoryContextDelete(relation->rd_pdcxt);
 	if (relation->rd_partcheck)
 		pfree(relation->rd_partcheck);
@@ -2546,6 +2563,27 @@ RelationClearRelation(Relation relation, bool rebuild)
 			SWAPFIELD(MemoryContext, rd_pdcxt);
 		}
 
+		/*
+		 * When the partdesc changes while the refcount is > 0 then we must
+		 * keep the original partdesc intact as it might currently be getting
+		 * used by some code.  We store the original partdesc in
+		 * rd_partdesc_orig.  If it changes multiple times we don't need to
+		 * keep the intermediate ones, just the original.  This gets cleared
+		 * up and set to NULL again when the ref count reaches 0.
+		 */
+		else if (relation->rd_partdesc != NULL && newrel->rd_partdesc != NULL &&
+			relation->rd_partdesc_orig == NULL)
+		{
+			relation->rd_partdesc_orig = newrel->rd_partdesc;
+			relation->rd_pdcxt_orig = newrel->rd_pdcxt;
+
+			/*
+			 * Set this so that RelationDestroyRelation does not destroy the
+			 * memory context of the original partdesc.
+			 */
+			newrel->rd_pdcxt_orig = newrel->rd_pdcxt;
+		}
+
 #undef SWAPFIELD
 
 		/* And now we can throw away the temporary entry */
@@ -5652,6 +5690,8 @@ load_relcache_init_file(bool shared)
 		rel->rd_partkey = NULL;
 		rel->rd_pdcxt = NULL;
 		rel->rd_partdesc = NULL;
+		rel->rd_pdcxt_orig = NULL;
+		rel->rd_partdesc_orig = NULL;
 		rel->rd_partcheck = NIL;
 		rel->rd_indexprs = NIL;
 		rel->rd_indpred = NIL;
diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h
index eb1858aa92..7724d8da15 100644
--- a/src/include/utils/rel.h
+++ b/src/include/utils/rel.h
@@ -99,6 +99,12 @@ typedef struct RelationData
 	struct PartitionKeyData *rd_partkey;	/* partition key, or NULL */
 	MemoryContext rd_pdcxt;		/* private context for partdesc */
 	struct PartitionDescData *rd_partdesc;	/* partitions, or NULL */
+	MemoryContext rd_pdcxt_orig;	/* private context for rd_partdesc_orig */
+	struct PartitionDescData *rd_partdesc_orig;	/* original partitions, or
+												 * NULL if not partitioned or
+												 * the rd_partdesc has not
+												 * changed while the ref count
+												 * was non-zero */
 	List	   *rd_partcheck;	/* partition CHECK quals */
 
 	/* data managed by RelationGetIndexList: */
