diff --git a/src/backend/bootstrap/bootparse.y b/src/backend/bootstrap/bootparse.y
index 6d7e11645d..d93ee723e1 100644
--- a/src/backend/bootstrap/bootparse.y
+++ b/src/backend/bootstrap/bootparse.y
@@ -328,6 +328,7 @@ Boot_DeclareIndexStmt:
 								false,
 								false,
 								true, /* skip_build */
+								false,
 								false);
 					do_end();
 				}
@@ -377,6 +378,7 @@ Boot_DeclareUniqueIndexStmt:
 								false,
 								false,
 								true, /* skip_build */
+								false,
 								false);
 					do_end();
 				}
diff --git a/src/backend/catalog/heap.c b/src/backend/catalog/heap.c
index 6b77eff0af..c031d7624c 100644
--- a/src/backend/catalog/heap.c
+++ b/src/backend/catalog/heap.c
@@ -379,18 +379,6 @@ heap_create(const char *relname,
 		relfilenode = relid;
 	}
 
-	/*
-	 * Never allow a pg_class entry to explicitly specify the database's
-	 * default tablespace in reltablespace; force it to zero instead. This
-	 * ensures that if the database is cloned with a different default
-	 * tablespace, the pg_class entry will still match where CREATE DATABASE
-	 * will put the physically copied relation.
-	 *
-	 * Yes, this is a bit of a hack.
-	 */
-	if (reltablespace == MyDatabaseTableSpace)
-		reltablespace = InvalidOid;
-
 	/*
 	 * build the relcache entry.
 	 */
diff --git a/src/backend/commands/indexcmds.c b/src/backend/commands/indexcmds.c
index 46f32c21f9..bc1d6e89a4 100644
--- a/src/backend/commands/indexcmds.c
+++ b/src/backend/commands/indexcmds.c
@@ -421,6 +421,8 @@ WaitForOlderSnapshots(TransactionId limitXmin, bool progress)
  *		case the caller had better have checked it earlier.
  * 'skip_build': make the catalog entries but don't create the index files
  * 'quiet': suppress the NOTICE chatter ordinarily provided for constraints.
+ * 'ignore_def_tblspc': If true and stmt->tablespace is empty then use the
+ *		database tablespace instead of consulting default_tablespace.
  *
  * Returns the object address of the created index.
  */
@@ -434,7 +436,8 @@ DefineIndex(Oid relationId,
 			bool check_rights,
 			bool check_not_in_use,
 			bool skip_build,
-			bool quiet)
+			bool quiet,
+			bool ignore_def_tblspc)
 {
 	char	   *indexRelationName;
 	char	   *accessMethodName;
@@ -623,11 +626,17 @@ DefineIndex(Oid relationId,
 	{
 		tablespaceId = get_tablespace_oid(stmt->tableSpace, false);
 	}
-	else
+	else if (!ignore_def_tblspc ||
+			 rel->rd_rel->relpersistence == RELPERSISTENCE_TEMP)
 	{
 		tablespaceId = GetDefaultTablespace(rel->rd_rel->relpersistence);
 		/* note InvalidOid is OK in this case */
 	}
+	else
+	{
+		/* use MyDatabaseTableSpace */
+		tablespaceId = InvalidOid;
+	}
 
 	/* Check tablespace permissions */
 	if (check_rights &&
@@ -1162,7 +1171,7 @@ DefineIndex(Oid relationId,
 								indexRelationId,	/* this is our child */
 								createdConstraintId,
 								is_alter_table, check_rights, check_not_in_use,
-								skip_build, quiet);
+								skip_build, quiet, false);
 				}
 
 				pgstat_progress_update_param(PROGRESS_CREATEIDX_PARTITIONS_DONE,
diff --git a/src/backend/commands/tablecmds.c b/src/backend/commands/tablecmds.c
index d48a947f7c..a39de5c6f3 100644
--- a/src/backend/commands/tablecmds.c
+++ b/src/backend/commands/tablecmds.c
@@ -654,8 +654,11 @@ DefineRelation(CreateStmt *stmt, char relkind, Oid ownerId,
 	}
 
 	/*
-	 * Select tablespace to use.  If not specified, use default tablespace
-	 * (which may in turn default to database's default).
+	 * Select tablespace to use.  If not specified and the table is a
+	 * partition, use its parent's tablespace, otherwise use default
+	 * tablespace (which may in turn default to database's default and
+	 * result in tablespaceId being set to InvalidOid).
+
 	 */
 	if (stmt->tablespacename)
 	{
@@ -663,22 +666,8 @@ DefineRelation(CreateStmt *stmt, char relkind, Oid ownerId,
 	}
 	else if (stmt->partbound)
 	{
-		HeapTuple	tup;
-
-		/*
-		 * For partitions, when no other tablespace is specified, we default
-		 * the tablespace to the parent partitioned table's.
-		 */
-		Assert(list_length(inheritOids) == 1);
-		tup = SearchSysCache1(RELOID,
-							  DatumGetObjectId(linitial_oid(inheritOids)));
-
-		tablespaceId = ((Form_pg_class) GETSTRUCT(tup))->reltablespace;
-
-		if (!OidIsValid(tablespaceId))
-			tablespaceId = GetDefaultTablespace(stmt->relation->relpersistence);
-
-		ReleaseSysCache(tup);
+		/* For table partitions, use the tablespace of its parent */
+		tablespaceId = get_rel_tablespace(linitial_oid(inheritOids));
 	}
 	else
 	{
@@ -687,7 +676,7 @@ DefineRelation(CreateStmt *stmt, char relkind, Oid ownerId,
 	}
 
 	/* Check permissions except when using database's default */
-	if (OidIsValid(tablespaceId) && tablespaceId != MyDatabaseTableSpace)
+	if (OidIsValid(tablespaceId))
 	{
 		AclResult	aclresult;
 
@@ -1076,7 +1065,7 @@ DefineRelation(CreateStmt *stmt, char relkind, Oid ownerId,
 						InvalidOid,
 						RelationGetRelid(idxRel),
 						constraintOid,
-						false, false, false, false, false);
+						false, false, false, false, false, false);
 
 			index_close(idxRel, AccessShareLock);
 		}
@@ -7093,7 +7082,8 @@ ATExecAddIndex(AlteredTableInfo *tab, Relation rel,
 						  check_rights,
 						  false,	/* check_not_in_use - we did it already */
 						  skip_build,
-						  quiet);
+						  quiet,
+						  is_rebuild);		/* ignore default_tablespace */
 
 	/*
 	 * If TryReuseIndex() stashed a relfilenode for us, we used it for the new
@@ -11201,12 +11191,17 @@ ATPostAlterTypeParse(Oid oldId, Oid oldRelId, Oid refRelId, char *cmd,
 		{
 			IndexStmt  *stmt = (IndexStmt *) stm;
 			AlterTableCmd *newcmd;
+			Oid			oldtablespace = get_rel_tablespace(oldId);
 
 			if (!rewrite)
 				TryReuseIndex(oldId, stmt);
 			/* keep the index's comment */
 			stmt->idxcomment = GetComment(oldId, RelationRelationId, 0);
 
+			if (OidIsValid(oldtablespace))
+				stmt->tableSpace = get_tablespace_name(oldtablespace);
+			else
+				stmt->tableSpace = NULL;
 			newcmd = makeNode(AlterTableCmd);
 			newcmd->subtype = AT_ReAddIndex;
 			newcmd->def = (Node *) stmt;
@@ -11226,9 +11221,11 @@ ATPostAlterTypeParse(Oid oldId, Oid oldRelId, Oid refRelId, char *cmd,
 				{
 					IndexStmt  *indstmt;
 					Oid			indoid;
+					Oid			oldtablespace;
 
 					indstmt = castNode(IndexStmt, cmd->def);
 					indoid = get_constraint_index(oldId);
+					oldtablespace = get_rel_tablespace(indoid);
 
 					if (!rewrite)
 						TryReuseIndex(indoid, indstmt);
@@ -11236,6 +11233,11 @@ ATPostAlterTypeParse(Oid oldId, Oid oldRelId, Oid refRelId, char *cmd,
 					indstmt->idxcomment = GetComment(indoid,
 													 RelationRelationId, 0);
 
+					if (OidIsValid(oldtablespace))
+						indstmt->tableSpace = get_tablespace_name(oldtablespace);
+					else
+						indstmt->tableSpace = NULL;
+
 					cmd->subtype = AT_ReAddIndex;
 					tab->subcmds[AT_PASS_OLD_INDEX] =
 						lappend(tab->subcmds[AT_PASS_OLD_INDEX], cmd);
@@ -15656,7 +15658,7 @@ AttachPartitionEnsureIndexes(Relation rel, Relation attachrel)
 			DefineIndex(RelationGetRelid(attachrel), stmt, InvalidOid,
 						RelationGetRelid(idxRel),
 						constraintOid,
-						true, false, false, false, false);
+						true, false, false, false, false, false);
 		}
 
 		index_close(idxRel, AccessShareLock);
diff --git a/src/backend/commands/tablespace.c b/src/backend/commands/tablespace.c
index 3784ea4b4f..7695d22a63 100644
--- a/src/backend/commands/tablespace.c
+++ b/src/backend/commands/tablespace.c
@@ -1117,8 +1117,6 @@ check_default_tablespace(char **newval, void **extra, GucSource source)
 Oid
 GetDefaultTablespace(char relpersistence)
 {
-	Oid			result;
-
 	/* The temp-table case is handled elsewhere */
 	if (relpersistence == RELPERSISTENCE_TEMP)
 	{
@@ -1137,15 +1135,7 @@ GetDefaultTablespace(char relpersistence)
 	 * to refer to an existing tablespace; we just silently return InvalidOid,
 	 * causing the new object to be created in the database's tablespace.
 	 */
-	result = get_tablespace_oid(default_tablespace, true);
-
-	/*
-	 * Allow explicit specification of database's default tablespace in
-	 * default_tablespace without triggering permissions checks.
-	 */
-	if (result == MyDatabaseTableSpace)
-		result = InvalidOid;
-	return result;
+	return get_tablespace_oid(default_tablespace, true);
 }
 
 
diff --git a/src/backend/tcop/utility.c b/src/backend/tcop/utility.c
index edf24c438c..933629f3eb 100644
--- a/src/backend/tcop/utility.c
+++ b/src/backend/tcop/utility.c
@@ -1366,7 +1366,8 @@ ProcessUtilitySlow(ParseState *pstate,
 									true,	/* check_rights */
 									true,	/* check_not_in_use */
 									false,	/* skip_build */
-									false); /* quiet */
+									false,	/* quiet */
+									false); /* ignore_def_tblspc */
 
 					/*
 					 * Add the CREATE INDEX node itself to stash right away;
diff --git a/src/include/commands/defrem.h b/src/include/commands/defrem.h
index 4003080323..569f6ec24c 100644
--- a/src/include/commands/defrem.h
+++ b/src/include/commands/defrem.h
@@ -33,7 +33,8 @@ extern ObjectAddress DefineIndex(Oid relationId,
 			bool check_rights,
 			bool check_not_in_use,
 			bool skip_build,
-			bool quiet);
+			bool quiet,
+			bool ignore_def_tblspc);
 extern void ReindexIndex(RangeVar *indexRelation, int options, bool concurrent);
 extern Oid	ReindexTable(RangeVar *relation, int options, bool concurrent);
 extern void ReindexMultipleTables(const char *objectName, ReindexObjectType objectKind,
