diff --git a/src/bin/pg_dump/common.c b/src/bin/pg_dump/common.c
index 37432a6f4b..75f1e358d8 100644
--- a/src/bin/pg_dump/common.c
+++ b/src/bin/pg_dump/common.c
@@ -775,6 +775,7 @@ getDumpableObjects(DumpableObject ***objs, int *numObjs)
 /*
  * Add a dependency link to a DumpableObject
  *
+ * To force refId appear before dobj.
  * Note: duplicate dependencies are currently not eliminated
  */
 void
diff --git a/src/bin/pg_dump/pg_dump.c b/src/bin/pg_dump/pg_dump.c
index 08658c8e86..01d5b37383 100644
--- a/src/bin/pg_dump/pg_dump.c
+++ b/src/bin/pg_dump/pg_dump.c
@@ -7132,9 +7132,19 @@ getIndexes(Archive *fout, TableInfo tblinfo[], int numTables)
 				constrinfo[j].condomain = NULL;
 				constrinfo[j].contype = contype;
 				if (contype == 'x')
+				{
 					constrinfo[j].condef = pg_strdup(PQgetvalue(res, j, i_condef));
+				}
 				else
+				{
 					constrinfo[j].condef = NULL;
+					/*
+					 * for these types constraint definition refers to the
+					 * index definition, which we also dump, so we need
+					 * to maintain the order
+					 */
+					addObjectDependency(&constrinfo[j].dobj, indxinfo[j].dobj.dumpId);
+				}
 				constrinfo[j].confrelid = InvalidOid;
 				constrinfo[j].conindex = indxinfo[j].dobj.dumpId;
 				constrinfo[j].condeferrable = *(PQgetvalue(res, j, i_condeferrable)) == 't';
@@ -7142,12 +7152,12 @@ getIndexes(Archive *fout, TableInfo tblinfo[], int numTables)
 				constrinfo[j].conislocal = true;
 				constrinfo[j].separate = true;
 
-				indxinfo[j].indexconstraint = constrinfo[j].dobj.dumpId;
+				indxinfo[j].indexconstraint = &constrinfo[j];
 			}
 			else
 			{
 				/* Plain secondary index */
-				indxinfo[j].indexconstraint = 0;
+				indxinfo[j].indexconstraint = NULL;
 			}
 		}
 
@@ -16355,7 +16365,9 @@ dumpIndex(Archive *fout, IndxInfo *indxinfo)
 {
 	DumpOptions *dopt = fout->dopt;
 	TableInfo  *tbinfo = indxinfo->indextable;
-	bool		is_constraint = (indxinfo->indexconstraint != 0);
+	bool		is_exclusion_constraint =
+		(indxinfo->indexconstraint != NULL &&
+		 indxinfo->indexconstraint->contype == 'x');
 	PQExpBuffer q;
 	PQExpBuffer delq;
 	char	   *qindxname;
@@ -16369,13 +16381,16 @@ dumpIndex(Archive *fout, IndxInfo *indxinfo)
 	qindxname = pg_strdup(fmtId(indxinfo->dobj.name));
 
 	/*
-	 * If there's an associated constraint, don't dump the index per se, but
+	 * If there's an associated EXCLUDE constraint, don't dump the index per se, but
 	 * do dump any comment for it.  (This is safe because dependency ordering
 	 * will have ensured the constraint is emitted first.)	Note that the
 	 * emitted comment has to be shown as depending on the constraint, not the
 	 * index, in such cases.
+	 * We need to dump indexes that support PRIMARY and UNIQUE constraints, as
+	 * such an index may have special options like collations which cannot be
+	 * expressed in the ALTER TABLE ... ADD CONSTRAINT statement.
 	 */
-	if (!is_constraint)
+	if (!is_exclusion_constraint)
 	{
 		char	   *indstatcols = indxinfo->indstatcols;
 		char	   *indstatvals = indxinfo->indstatvals;
@@ -16469,8 +16484,9 @@ dumpIndex(Archive *fout, IndxInfo *indxinfo)
 					tbinfo->dobj.namespace->dobj.name,
 					tbinfo->rolname,
 					indxinfo->dobj.catId, 0,
-					is_constraint ? indxinfo->indexconstraint :
-					indxinfo->dobj.dumpId);
+					is_exclusion_constraint ?
+						indxinfo->indexconstraint->dobj.dumpId :
+						indxinfo->dobj.dumpId);
 
 	destroyPQExpBuffer(q);
 	destroyPQExpBuffer(delq);
@@ -16635,47 +16651,9 @@ dumpConstraint(Archive *fout, ConstraintInfo *coninfo)
 		}
 		else
 		{
-			appendPQExpBuffer(q, "%s (",
-							  coninfo->contype == 'p' ? "PRIMARY KEY" : "UNIQUE");
-			for (k = 0; k < indxinfo->indnkeyattrs; k++)
-			{
-				int			indkey = (int) indxinfo->indkeys[k];
-				const char *attname;
-
-				if (indkey == InvalidAttrNumber)
-					break;
-				attname = getAttrName(indkey, tbinfo);
-
-				appendPQExpBuffer(q, "%s%s",
-								  (k == 0) ? "" : ", ",
-								  fmtId(attname));
-			}
-
-			if (indxinfo->indnkeyattrs < indxinfo->indnattrs)
-				appendPQExpBufferStr(q, ") INCLUDE (");
-
-			for (k = indxinfo->indnkeyattrs; k < indxinfo->indnattrs; k++)
-			{
-				int			indkey = (int) indxinfo->indkeys[k];
-				const char *attname;
-
-				if (indkey == InvalidAttrNumber)
-					break;
-				attname = getAttrName(indkey, tbinfo);
-
-				appendPQExpBuffer(q, "%s%s",
-								  (k == indxinfo->indnkeyattrs) ? "" : ", ",
-								  fmtId(attname));
-			}
-
-			appendPQExpBufferChar(q, ')');
-
-			if (nonemptyReloptions(indxinfo->indreloptions))
-			{
-				appendPQExpBufferStr(q, " WITH (");
-				appendReloptionsArrayAH(q, indxinfo->indreloptions, "", fout);
-				appendPQExpBufferChar(q, ')');
-			}
+			appendPQExpBuffer(q, "%s USING INDEX %s",
+							  coninfo->contype == 'p' ? "PRIMARY KEY" : "UNIQUE",
+							  fmtId(indxinfo->dobj.name));
 
 			if (coninfo->condeferrable)
 			{
diff --git a/src/bin/pg_dump/pg_dump.h b/src/bin/pg_dump/pg_dump.h
index 7b2c1524a5..7984566b93 100644
--- a/src/bin/pg_dump/pg_dump.h
+++ b/src/bin/pg_dump/pg_dump.h
@@ -351,6 +351,29 @@ typedef struct _tableDataInfo
 	char	   *filtercond;		/* WHERE condition to limit rows dumped */
 } TableDataInfo;
 
+/*
+ * struct ConstraintInfo is used for all constraint types.  However we
+ * use a different objType for foreign key constraints, to make it easier
+ * to sort them the way we want.
+ *
+ * Note: condeferrable and condeferred are currently only valid for
+ * unique/primary-key constraints.  Otherwise that info is in condef.
+ */
+typedef struct _constraintInfo
+{
+	DumpableObject dobj;
+	TableInfo  *contable;		/* NULL if domain constraint */
+	TypeInfo   *condomain;		/* NULL if table constraint */
+	char		contype;
+	char	   *condef;			/* definition, if CHECK or FOREIGN KEY */
+	Oid			confrelid;		/* referenced table, if FOREIGN KEY */
+	DumpId		conindex;		/* identifies associated index if any */
+	bool		condeferrable;	/* true if constraint is DEFERRABLE */
+	bool		condeferred;	/* true if constraint is INITIALLY DEFERRED */
+	bool		conislocal;		/* true if constraint has local definition */
+	bool		separate;		/* true if must dump as separate item */
+} ConstraintInfo;
+
 typedef struct _indxInfo
 {
 	DumpableObject dobj;
@@ -369,8 +392,8 @@ typedef struct _indxInfo
 	Oid			parentidx;		/* if partitioned, parent index OID */
 	SimplePtrList partattaches;	/* if partitioned, partition attach objects */
 
-	/* if there is an associated constraint object, its dumpId: */
-	DumpId		indexconstraint;
+	/* an associated constraint object, or NULL if none */
+	ConstraintInfo *indexconstraint;
 } IndxInfo;
 
 typedef struct _indexAttachInfo
@@ -427,29 +450,6 @@ typedef struct _evttriggerInfo
 	char		evtenabled;
 } EventTriggerInfo;
 
-/*
- * struct ConstraintInfo is used for all constraint types.  However we
- * use a different objType for foreign key constraints, to make it easier
- * to sort them the way we want.
- *
- * Note: condeferrable and condeferred are currently only valid for
- * unique/primary-key constraints.  Otherwise that info is in condef.
- */
-typedef struct _constraintInfo
-{
-	DumpableObject dobj;
-	TableInfo  *contable;		/* NULL if domain constraint */
-	TypeInfo   *condomain;		/* NULL if table constraint */
-	char		contype;
-	char	   *condef;			/* definition, if CHECK or FOREIGN KEY */
-	Oid			confrelid;		/* referenced table, if FOREIGN KEY */
-	DumpId		conindex;		/* identifies associated index if any */
-	bool		condeferrable;	/* true if constraint is DEFERRABLE */
-	bool		condeferred;	/* true if constraint is INITIALLY DEFERRED */
-	bool		conislocal;		/* true if constraint has local definition */
-	bool		separate;		/* true if must dump as separate item */
-} ConstraintInfo;
-
 typedef struct _procLangInfo
 {
 	DumpableObject dobj;
diff --git a/src/bin/pg_dump/t/002_pg_dump.pl b/src/bin/pg_dump/t/002_pg_dump.pl
index 1163420491..9938e2754a 100644
--- a/src/bin/pg_dump/t/002_pg_dump.pl
+++ b/src/bin/pg_dump/t/002_pg_dump.pl
@@ -615,10 +615,26 @@ my %tests = (
 		},
 	},
 
+	'CREATE UNIQUE INDEX ON test_table ... (for primary key)' => {
+		regexp => qr/^
+			\QCREATE UNIQUE INDEX test_table_pkey ON dump_test.test_table USING btree (col1);\E
+			/xm,
+		like => {
+			%full_runs,
+			%dump_test_schema_runs,
+			only_dump_test_table => 1,
+			section_post_data    => 1,
+		},
+		unlike => {
+			exclude_dump_test_schema => 1,
+			exclude_test_table       => 1,
+		},
+	},
+
 	'ALTER TABLE ONLY test_table ADD CONSTRAINT ... PRIMARY KEY' => {
 		regexp => qr/^
 			\QALTER TABLE ONLY dump_test.test_table\E \n^\s+
-			\QADD CONSTRAINT test_table_pkey PRIMARY KEY (col1);\E
+			\QADD CONSTRAINT test_table_pkey PRIMARY KEY USING INDEX test_table_pkey;\E
 			/xm,
 		like => {
 			%full_runs,
@@ -2607,6 +2623,17 @@ my %tests = (
 		},
 	},
 
+	'CREATE UNIQUE INDEX ON measurement ... (for primary key)' => {
+		all_runs     => 1,
+		catch_all    => 'CREATE ... commands',
+		regexp => qr/^
+			\QCREATE UNIQUE INDEX measurement_pkey ON ONLY dump_test.measurement USING btree (city_id, logdate);\E
+		/xm,
+		like =>
+		  { %full_runs, %dump_test_schema_runs, section_post_data => 1, },
+		unlike => { exclude_dump_test_schema => 1, },
+	},
+
 	'ALTER TABLE measurement PRIMARY KEY' => {
 		all_runs     => 1,
 		catch_all    => 'CREATE ... commands',
@@ -2615,7 +2642,7 @@ my %tests = (
 		  'ALTER TABLE dump_test.measurement ADD PRIMARY KEY (city_id, logdate);',
 		regexp => qr/^
 			\QALTER TABLE ONLY dump_test.measurement\E \n^\s+
-			\QADD CONSTRAINT measurement_pkey PRIMARY KEY (city_id, logdate);\E
+			\QADD CONSTRAINT measurement_pkey PRIMARY KEY USING INDEX measurement_pkey;\E
 		/xm,
 		like =>
 		  { %full_runs, %dump_test_schema_runs, section_post_data => 1, },
