diff --git a/src/bin/psql/describe.c b/src/bin/psql/describe.c
index cd829e0759..e65fa07049 100644
--- a/src/bin/psql/describe.c
+++ b/src/bin/psql/describe.c
@@ -28,6 +28,7 @@
 #include "settings.h"
 #include "variables.h"
 
+static const char *map_typename_pattern(const char *pattern);
 static bool describeOneTableDetails(const char *schemaname,
 									const char *relationname,
 									const char *oid,
@@ -663,7 +664,8 @@ describeFunctions(const char *functypes, const char *func_pattern,
 					 "pg_catalog.format_type(t%d.oid, NULL)", i);
 			snprintf(tiv, sizeof(tiv),
 					 "pg_catalog.pg_type_is_visible(t%d.oid)", i);
-			processSQLNamePattern(pset.db, &buf, arg_patterns[i],
+			processSQLNamePattern(pset.db, &buf,
+								  map_typename_pattern(arg_patterns[i]),
 								  true, false,
 								  nspname, typname, ft, tiv);
 		}
@@ -787,20 +789,24 @@ describeTypes(const char *pattern, bool verbose, bool showSystem)
 						 "WHERE c.oid = t.typrelid))\n");
 
 	/*
-	 * do not include array types (before 8.3 we have to use the assumption
-	 * that their names start with underscore)
+	 * do not include array types unless the pattern contains [] (before 8.3
+	 * we have to use the assumption that their names start with underscore)
 	 */
-	if (pset.sversion >= 80300)
-		appendPQExpBufferStr(&buf, "  AND NOT EXISTS(SELECT 1 FROM pg_catalog.pg_type el WHERE el.oid = t.typelem AND el.typarray = t.oid)\n");
-	else
-		appendPQExpBufferStr(&buf, "  AND t.typname !~ '^_'\n");
+	if (strstr(pattern, "[]") == NULL)
+	{
+		if (pset.sversion >= 80300)
+			appendPQExpBufferStr(&buf, "  AND NOT EXISTS(SELECT 1 FROM pg_catalog.pg_type el WHERE el.oid = t.typelem AND el.typarray = t.oid)\n");
+		else
+			appendPQExpBufferStr(&buf, "  AND t.typname !~ '^_'\n");
+	}
 
 	if (!showSystem && !pattern)
 		appendPQExpBufferStr(&buf, "      AND n.nspname <> 'pg_catalog'\n"
 							 "      AND n.nspname <> 'information_schema'\n");
 
 	/* Match name pattern against either internal or external name */
-	processSQLNamePattern(pset.db, &buf, pattern, true, false,
+	processSQLNamePattern(pset.db, &buf, map_typename_pattern(pattern),
+						  true, false,
 						  "n.nspname", "t.typname",
 						  "pg_catalog.format_type(t.oid, NULL)",
 						  "pg_catalog.pg_type_is_visible(t.oid)");
@@ -822,6 +828,60 @@ describeTypes(const char *pattern, bool verbose, bool showSystem)
 	return true;
 }
 
+/*
+ * Map some variant type names accepted by the backend grammar into
+ * canonical type names.
+ *
+ * Helper for \dT and other functions that take typename patterns.
+ * This doesn't completely mask the fact that these names are special;
+ * for example, a pattern of "dec*" won't magically match "numeric".
+ * But it goes a long way to reduce the surprise factor.
+ */
+static const char *
+map_typename_pattern(const char *pattern)
+{
+	static const char *const typename_map[] = {
+		/*
+		 * These names are accepted by gram.y, although they are neither the
+		 * "real" name seen in pg_type nor the canonical name printed by
+		 * format_type().
+		 */
+		"decimal", "numeric",
+		"float", "double precision",
+		"int", "integer",
+
+		/*
+		 * We also have to map the array names for cases where the canonical
+		 * name is different from what pg_type says.
+		 */
+		"bool[]", "boolean[]",
+		"decimal[]", "numeric[]",
+		"float[]", "double precision[]",
+		"float4[]", "real[]",
+		"float8[]", "double precision[]",
+		"int[]", "integer[]",
+		"int2[]", "smallint[]",
+		"int4[]", "integer[]",
+		"int8[]", "bigint[]",
+		"time[]", "time without time zone[]",
+		"timetz[]", "time with time zone[]",
+		"timestamp[]", "timestamp without time zone[]",
+		"timestamptz[]", "timestamp with time zone[]",
+		"varbit[]", "bit varying[]",
+		"varchar[]", "character varying[]",
+		NULL
+	};
+
+	if (pattern == NULL)
+		return NULL;
+	for (int i = 0; typename_map[i] != NULL; i += 2)
+	{
+		if (strcmp(pattern, typename_map[i]) == 0)
+			return typename_map[i + 1];
+	}
+	return pattern;
+}
+
 
 /*
  * \do
@@ -927,7 +987,8 @@ describeOperators(const char *oper_pattern,
 					 "pg_catalog.format_type(t%d.oid, NULL)", i);
 			snprintf(tiv, sizeof(tiv),
 					 "pg_catalog.pg_type_is_visible(t%d.oid)", i);
-			processSQLNamePattern(pset.db, &buf, arg_patterns[i],
+			processSQLNamePattern(pset.db, &buf,
+								  map_typename_pattern(arg_patterns[i]),
 								  true, false,
 								  nspname, typname, ft, tiv);
 		}
