diff --git a/src/backend/catalog/pg_type.c b/src/backend/catalog/pg_type.c
index 04c10c6347b81183aa5c5ec3906bc0367672da29..74eeba6e0ab3aa127c1ba01e2c37b770f92629cd 100644
*** a/src/backend/catalog/pg_type.c
--- b/src/backend/catalog/pg_type.c
*************** RenameTypeInternal(Oid typeOid, const ch
*** 695,700 ****
--- 695,701 ----
  	HeapTuple	tuple;
  	Form_pg_type typ;
  	Oid			arrayOid;
+ 	Oid			oldTypeOid;
  
  	pg_type_desc = heap_open(TypeRelationId, RowExclusiveLock);
  
*************** RenameTypeInternal(Oid typeOid, const ch
*** 708,720 ****
  
  	arrayOid = typ->typarray;
  
! 	/* Just to give a more friendly error than unique-index violation */
! 	if (SearchSysCacheExists2(TYPENAMENSP,
! 							  CStringGetDatum(newTypeName),
! 							  ObjectIdGetDatum(typeNamespace)))
! 		ereport(ERROR,
! 				(errcode(ERRCODE_DUPLICATE_OBJECT),
! 				 errmsg("type \"%s\" already exists", newTypeName)));
  
  	/* OK, do the rename --- tuple is a copy, so OK to scribble on it */
  	namestrcpy(&(typ->typname), newTypeName);
--- 709,736 ----
  
  	arrayOid = typ->typarray;
  
! 	/* Check for a conflicting type name. */
! 	oldTypeOid = GetSysCacheOid2(TYPENAMENSP,
! 								 CStringGetDatum(newTypeName),
! 								 ObjectIdGetDatum(typeNamespace));
! 
! 	/*
! 	 * If there is one, see if it's an autogenerated array type, and if so
! 	 * rename it out of the way.  (But we must skip that for a shell type
! 	 * because moveArrayTypeName will do the wrong thing in that case.)
! 	 * Otherwise, we can at least give a more friendly error than unique-index
! 	 * violation.
! 	 */
! 	if (OidIsValid(oldTypeOid))
! 	{
! 		if (get_typisdefined(oldTypeOid) &&
! 			moveArrayTypeName(oldTypeOid, newTypeName, typeNamespace))
! 			/* successfully dodged the problem */ ;
! 		else
! 			ereport(ERROR,
! 					(errcode(ERRCODE_DUPLICATE_OBJECT),
! 					 errmsg("type \"%s\" already exists", newTypeName)));
! 	}
  
  	/* OK, do the rename --- tuple is a copy, so OK to scribble on it */
  	namestrcpy(&(typ->typname), newTypeName);
*************** RenameTypeInternal(Oid typeOid, const ch
*** 726,733 ****
  	heap_freetuple(tuple);
  	heap_close(pg_type_desc, RowExclusiveLock);
  
! 	/* If the type has an array type, recurse to handle that */
! 	if (OidIsValid(arrayOid))
  	{
  		char	   *arrname = makeArrayTypeName(newTypeName, typeNamespace);
  
--- 742,753 ----
  	heap_freetuple(tuple);
  	heap_close(pg_type_desc, RowExclusiveLock);
  
! 	/*
! 	 * If the type has an array type, recurse to handle that.  But we don't
! 	 * need to do anything more if we already renamed that array type above
! 	 * (which would happen when, eg, renaming "foo" to "_foo").
! 	 */
! 	if (OidIsValid(arrayOid) && arrayOid != oldTypeOid)
  	{
  		char	   *arrname = makeArrayTypeName(newTypeName, typeNamespace);
  
diff --git a/src/test/regress/expected/alter_table.out b/src/test/regress/expected/alter_table.out
index c88fd768482792bd8376dd21cc5b63be927f7727..8aadbb88a348571dd2fe6e22d1e2a2f72380d35b 100644
*** a/src/test/regress/expected/alter_table.out
--- b/src/test/regress/expected/alter_table.out
*************** SELECT * FROM tmp_new2;
*** 128,133 ****
--- 128,182 ----
  
  DROP TABLE tmp_new;
  DROP TABLE tmp_new2;
+ --
+ -- check renaming to a table's array type's autogenerated name
+ -- (the array type's name should get out of the way)
+ --
+ CREATE TABLE tmp_array (id int);
+ CREATE TABLE tmp_array2 (id int);
+ SELECT typname FROM pg_type WHERE oid = 'tmp_array[]'::regtype;
+   typname   
+ ------------
+  _tmp_array
+ (1 row)
+ 
+ SELECT typname FROM pg_type WHERE oid = 'tmp_array2[]'::regtype;
+    typname   
+ -------------
+  _tmp_array2
+ (1 row)
+ 
+ ALTER TABLE tmp_array2 RENAME TO _tmp_array;
+ SELECT typname FROM pg_type WHERE oid = 'tmp_array[]'::regtype;
+    typname   
+ -------------
+  __tmp_array
+ (1 row)
+ 
+ SELECT typname FROM pg_type WHERE oid = '_tmp_array[]'::regtype;
+    typname    
+ --------------
+  ___tmp_array
+ (1 row)
+ 
+ DROP TABLE _tmp_array;
+ DROP TABLE tmp_array;
+ -- renaming to table's own array type's name is an interesting corner case
+ CREATE TABLE tmp_array (id int);
+ SELECT typname FROM pg_type WHERE oid = 'tmp_array[]'::regtype;
+   typname   
+ ------------
+  _tmp_array
+ (1 row)
+ 
+ ALTER TABLE tmp_array RENAME TO _tmp_array;
+ SELECT typname FROM pg_type WHERE oid = '_tmp_array[]'::regtype;
+    typname   
+ -------------
+  __tmp_array
+ (1 row)
+ 
+ DROP TABLE _tmp_array;
  -- ALTER TABLE ... RENAME on non-table relations
  -- renaming indexes (FIXME: this should probably test the index's functionality)
  ALTER INDEX IF EXISTS __onek_unique1 RENAME TO tmp_onek_unique1;
diff --git a/src/test/regress/sql/alter_table.sql b/src/test/regress/sql/alter_table.sql
index c0e29720dc5dbd6ef0b230ae129a32f5c1f456f0..c41b48785b5cdf2f4ad76ea8ec414059b6de1824 100644
*** a/src/test/regress/sql/alter_table.sql
--- b/src/test/regress/sql/alter_table.sql
*************** SELECT * FROM tmp_new2;
*** 165,170 ****
--- 165,190 ----
  DROP TABLE tmp_new;
  DROP TABLE tmp_new2;
  
+ --
+ -- check renaming to a table's array type's autogenerated name
+ -- (the array type's name should get out of the way)
+ --
+ CREATE TABLE tmp_array (id int);
+ CREATE TABLE tmp_array2 (id int);
+ SELECT typname FROM pg_type WHERE oid = 'tmp_array[]'::regtype;
+ SELECT typname FROM pg_type WHERE oid = 'tmp_array2[]'::regtype;
+ ALTER TABLE tmp_array2 RENAME TO _tmp_array;
+ SELECT typname FROM pg_type WHERE oid = 'tmp_array[]'::regtype;
+ SELECT typname FROM pg_type WHERE oid = '_tmp_array[]'::regtype;
+ DROP TABLE _tmp_array;
+ DROP TABLE tmp_array;
+ 
+ -- renaming to table's own array type's name is an interesting corner case
+ CREATE TABLE tmp_array (id int);
+ SELECT typname FROM pg_type WHERE oid = 'tmp_array[]'::regtype;
+ ALTER TABLE tmp_array RENAME TO _tmp_array;
+ SELECT typname FROM pg_type WHERE oid = '_tmp_array[]'::regtype;
+ DROP TABLE _tmp_array;
  
  -- ALTER TABLE ... RENAME on non-table relations
  -- renaming indexes (FIXME: this should probably test the index's functionality)
