diff --git a/src/backend/catalog/pg_depend.c b/src/backend/catalog/pg_depend.c
index 2ea05f350b330ace23d214f33de8e656318f6e99..c6f75c5aa8f2c23d91aa3f6024dcdfc4ab20e3d8 100644
--- a/src/backend/catalog/pg_depend.c
+++ b/src/backend/catalog/pg_depend.c
@@ -616,8 +616,8 @@ getOwnedSequence(Oid relid, AttrNumber attnum)
 
 /*
  * get_constraint_index
- *		Given the OID of a unique or primary-key constraint, return the
- *		OID of the underlying unique index.
+ *		Given the OID of a unique, primary-key, or exclusion constraint,
+ *		return the OID of the underlying index.
  *
  * Return InvalidOid if the index couldn't be found; this suggests the
  * given OID is bogus, but we leave it to caller to decide what to do.
@@ -664,10 +664,13 @@ get_constraint_index(Oid constraintId)
 		{
 			char		relkind = get_rel_relkind(deprec->objid);
 
-			/* This is pure paranoia; there shouldn't be any such */
+			/*
+			 * This is pure paranoia; there shouldn't be any other relkinds
+			 * dependent on a constraint.
+			 */
 			if (relkind != RELKIND_INDEX &&
 				relkind != RELKIND_PARTITIONED_INDEX)
-				break;
+				continue;
 
 			indexId = deprec->objid;
 			break;
@@ -682,8 +685,9 @@ get_constraint_index(Oid constraintId)
 
 /*
  * get_index_constraint
- *		Given the OID of an index, return the OID of the owning unique or
- *		primary-key constraint, or InvalidOid if no such constraint.
+ *		Given the OID of an index, return the OID of the owning unique,
+ *		primary-key, or exclusion constraint, or InvalidOid if there
+ *		is no owning constraint.
  */
 Oid
 get_index_constraint(Oid indexId)
diff --git a/src/backend/commands/tablecmds.c b/src/backend/commands/tablecmds.c
index 96e85bd6ced652bc352a85ce443ecb35d083d328..5c278463c6d56239ef00f3bb852150f2fd659c3a 100644
--- a/src/backend/commands/tablecmds.c
+++ b/src/backend/commands/tablecmds.c
@@ -9785,6 +9785,9 @@ ATExecAlterColumnType(AlteredTableInfo *tab, Relation rel,
 	SysScanDesc scan;
 	HeapTuple	depTup;
 	ObjectAddress address;
+	ListCell   *lc;
+	ListCell   *prev;
+	ListCell   *next;
 
 	/*
 	 * Clear all the missing values if we're rewriting the table, since this
@@ -9915,14 +9918,20 @@ ATExecAlterColumnType(AlteredTableInfo *tab, Relation rel,
 					if (relKind == RELKIND_INDEX ||
 						relKind == RELKIND_PARTITIONED_INDEX)
 					{
+						/*
+						 * Indexes that are directly dependent on the table
+						 * might be regular indexes or constraint indexes.
+						 * Constraint indexes typically have only indirect
+						 * dependencies; but there are exceptions, notably
+						 * partial exclusion constraints.  Hence we must check
+						 * whether the index depends on any constraint that's
+						 * due to be rebuilt, which we'll do below after we've
+						 * found all such constraints.
+						 */
 						Assert(foundObject.objectSubId == 0);
-						if (!list_member_oid(tab->changedIndexOids, foundObject.objectId))
-						{
-							tab->changedIndexOids = lappend_oid(tab->changedIndexOids,
-																foundObject.objectId);
-							tab->changedIndexDefs = lappend(tab->changedIndexDefs,
-															pg_get_indexdef_string(foundObject.objectId));
-						}
+						tab->changedIndexOids =
+							list_append_unique_oid(tab->changedIndexOids,
+												   foundObject.objectId);
 					}
 					else if (relKind == RELKIND_SEQUENCE)
 					{
@@ -10073,6 +10082,41 @@ ATExecAlterColumnType(AlteredTableInfo *tab, Relation rel,
 
 	systable_endscan(scan);
 
+	/*
+	 * Check the collected index OIDs to see which ones belong to the
+	 * constraint(s) of the table, and drop those from the list of indexes
+	 * that we need to process; rebuilding the constraints will handle them.
+	 */
+	prev = NULL;
+	for (lc = list_head(tab->changedIndexOids); lc; lc = next)
+	{
+		Oid			indexoid = lfirst_oid(lc);
+		Oid			conoid;
+
+		next = lnext(lc);
+
+		conoid = get_index_constraint(indexoid);
+		if (OidIsValid(conoid) &&
+			list_member_oid(tab->changedConstraintOids, conoid))
+			tab->changedIndexOids = list_delete_cell(tab->changedIndexOids,
+													 lc, prev);
+		else
+			prev = lc;
+	}
+
+	/*
+	 * Now collect the definitions of the indexes that must be rebuilt.  (We
+	 * could merge this into the previous loop, but it'd be more complicated
+	 * for little gain.)
+	 */
+	foreach(lc, tab->changedIndexOids)
+	{
+		Oid			indexoid = lfirst_oid(lc);
+
+		tab->changedIndexDefs = lappend(tab->changedIndexDefs,
+										pg_get_indexdef_string(indexoid));
+	}
+
 	/*
 	 * Now scan for dependencies of this column on other things.  The only
 	 * thing we should find is the dependency on the column datatype, which we
diff --git a/src/test/regress/expected/alter_table.out b/src/test/regress/expected/alter_table.out
index c3a650d4f281f1a6df0d4c318839d16d5bc6119e..ed11538568ad745686e756a0a76637dda3434388 100644
--- a/src/test/regress/expected/alter_table.out
+++ b/src/test/regress/expected/alter_table.out
@@ -1990,6 +1990,46 @@ select * from anothertab;
  f      | IT WAS NULL!
 (3 rows)
 
+drop table anothertab;
+-- Test alter table column type with constraint indexes (cf. bug #15835)
+create table anothertab(f1 int primary key, f2 int unique, f3 int, f4 int);
+alter table anothertab
+  add exclude using btree (f3 with =);
+alter table anothertab
+  add exclude using btree (f4 with =) where (f4 is not null);
+\d anothertab
+             Table "public.anothertab"
+ Column |  Type   | Collation | Nullable | Default 
+--------+---------+-----------+----------+---------
+ f1     | integer |           | not null | 
+ f2     | integer |           |          | 
+ f3     | integer |           |          | 
+ f4     | integer |           |          | 
+Indexes:
+    "anothertab_pkey" PRIMARY KEY, btree (f1)
+    "anothertab_f2_key" UNIQUE CONSTRAINT, btree (f2)
+    "anothertab_f3_excl" EXCLUDE USING btree (f3 WITH =)
+    "anothertab_f4_excl" EXCLUDE USING btree (f4 WITH =) WHERE (f4 IS NOT NULL)
+
+alter table anothertab alter column f1 type bigint;
+alter table anothertab
+  alter column f2 type bigint,
+  alter column f3 type bigint,
+  alter column f4 type bigint;
+\d anothertab
+            Table "public.anothertab"
+ Column |  Type  | Collation | Nullable | Default 
+--------+--------+-----------+----------+---------
+ f1     | bigint |           | not null | 
+ f2     | bigint |           |          | 
+ f3     | bigint |           |          | 
+ f4     | bigint |           |          | 
+Indexes:
+    "anothertab_pkey" PRIMARY KEY, btree (f1)
+    "anothertab_f2_key" UNIQUE CONSTRAINT, btree (f2)
+    "anothertab_f3_excl" EXCLUDE USING btree (f3 WITH =)
+    "anothertab_f4_excl" EXCLUDE USING btree (f4 WITH =) WHERE (f4 IS NOT NULL)
+
 drop table anothertab;
 create table another (f1 int, f2 text);
 insert into another values(1, 'one');
diff --git a/src/test/regress/sql/alter_table.sql b/src/test/regress/sql/alter_table.sql
index abb3a6aa1348a09d801911dcef4103d359157c08..d5c3b931315b009d8a85c9c192a31d31e1c038e9 100644
--- a/src/test/regress/sql/alter_table.sql
+++ b/src/test/regress/sql/alter_table.sql
@@ -1357,6 +1357,23 @@ select * from anothertab;
 
 drop table anothertab;
 
+-- Test alter table column type with constraint indexes (cf. bug #15835)
+create table anothertab(f1 int primary key, f2 int unique, f3 int, f4 int);
+alter table anothertab
+  add exclude using btree (f3 with =);
+alter table anothertab
+  add exclude using btree (f4 with =) where (f4 is not null);
+
+\d anothertab
+alter table anothertab alter column f1 type bigint;
+alter table anothertab
+  alter column f2 type bigint,
+  alter column f3 type bigint,
+  alter column f4 type bigint;
+\d anothertab
+
+drop table anothertab;
+
 create table another (f1 int, f2 text);
 
 insert into another values(1, 'one');