diff --git a/doc/src/sgml/maintenance.sgml b/doc/src/sgml/maintenance.sgml
index 9e3e3c5ac430fcbef67d475a52434384f0169064..7bb67b05ab67508499f46b62fe05bb625c5d819a 100644
--- a/doc/src/sgml/maintenance.sgml
+++ b/doc/src/sgml/maintenance.sgml
@@ -534,7 +534,7 @@
     examine this information is to execute queries such as:
 
 <programlisting>
-SELECT relname, age(relfrozenxid) FROM pg_class WHERE relkind = 'r';
+SELECT relname, age(relfrozenxid) FROM pg_class WHERE relkind IN ('r', 'm');
 SELECT datname, age(datfrozenxid) FROM pg_database;
 </programlisting>
 
diff --git a/src/backend/access/heap/tuptoaster.c b/src/backend/access/heap/tuptoaster.c
index c76dc24260d7bdc543778f4590677d8e70603dbb..672846949926ab00765efa717e15cd25205a0db7 100644
--- a/src/backend/access/heap/tuptoaster.c
+++ b/src/backend/access/heap/tuptoaster.c
@@ -512,8 +512,8 @@ toast_insert_or_update(Relation rel, HeapTuple newtup, HeapTuple oldtup,
 	bool		toast_delold[MaxHeapAttributeNumber];
 
 	/*
-	 * We should only ever be called for tuples of plain relations ---
-	 * recursing on a toast rel is bad news.
+	 * We should only ever be called for tuples of plain relations or
+	 * materialized views --- recursing on a toast rel is bad news.
 	 */
 	Assert(rel->rd_rel->relkind == RELKIND_RELATION ||
 		   rel->rd_rel->relkind == RELKIND_MATVIEW);
diff --git a/src/backend/catalog/aclchk.c b/src/backend/catalog/aclchk.c
index e0dcf05687c57a4a34008916ace45564245ad693..97bc93ccd636a7977376ee518b5cef3d927b0e8b 100644
--- a/src/backend/catalog/aclchk.c
+++ b/src/backend/catalog/aclchk.c
@@ -761,7 +761,6 @@ objectsInSchemaToOids(GrantObjectType objtype, List *nspnames)
 		switch (objtype)
 		{
 			case ACL_OBJECT_RELATION:
-				/* Process regular tables, views and foreign tables */
 				objs = getRelationsInNamespace(namespaceId, RELKIND_RELATION);
 				objects = list_concat(objects, objs);
 				objs = getRelationsInNamespace(namespaceId, RELKIND_VIEW);
diff --git a/src/backend/catalog/heap.c b/src/backend/catalog/heap.c
index f1cdef9e130ddcf42a0c306441edf1c5deef2101..64ca3121b32771d7c8db30a84b81f4b6acd97574 100644
--- a/src/backend/catalog/heap.c
+++ b/src/backend/catalog/heap.c
@@ -1152,9 +1152,8 @@ heap_create_with_catalog(const char *relname,
 	/*
 	 * Decide whether to create an array type over the relation's rowtype. We
 	 * do not create any array types for system catalogs (ie, those made
-	 * during initdb).	We create array types for regular relations, views,
-	 * composite types and foreign tables ... but not, eg, for toast tables or
-	 * sequences.
+	 * during initdb). We do not create them where the use of a relation as
+	 * such is an implementation detail: toast tables, sequences and indexes.
 	 */
 	if (IsUnderPostmaster && (relkind == RELKIND_RELATION ||
 							  relkind == RELKIND_VIEW ||
diff --git a/src/backend/commands/comment.c b/src/backend/commands/comment.c
index 8baf01738049335d1b0ffbcbd1eba3f02f8c69d7..5ecc92afac61545503de0ba260860add48827257 100644
--- a/src/backend/commands/comment.c
+++ b/src/backend/commands/comment.c
@@ -98,7 +98,7 @@ CommentObject(CommentStmt *stmt)
 				relation->rd_rel->relkind != RELKIND_FOREIGN_TABLE)
 				ereport(ERROR,
 						(errcode(ERRCODE_WRONG_OBJECT_TYPE),
-						 errmsg("\"%s\" is not a table, view, composite type, or foreign table",
+						 errmsg("\"%s\" is not a table, view, materialized view, composite type, or foreign table",
 								RelationGetRelationName(relation))));
 			break;
 		default:
diff --git a/src/backend/commands/indexcmds.c b/src/backend/commands/indexcmds.c
index 9d9745e714f83a137c01a8b3e7609640a9c396dc..ec8f248eea6005089d160f11fd5aef1064b497a7 100644
--- a/src/backend/commands/indexcmds.c
+++ b/src/backend/commands/indexcmds.c
@@ -372,7 +372,7 @@ DefineIndex(IndexStmt *stmt,
 		else
 			ereport(ERROR,
 					(errcode(ERRCODE_WRONG_OBJECT_TYPE),
-					 errmsg("\"%s\" is not a table",
+					 errmsg("\"%s\" is not a table or materialized view",
 							RelationGetRelationName(rel))));
 	}
 
@@ -1834,8 +1834,8 @@ ReindexDatabase(const char *databaseName, bool do_system, bool do_user)
 	/*
 	 * Scan pg_class to build a list of the relations we need to reindex.
 	 *
-	 * We only consider plain relations here (toast rels will be processed
-	 * indirectly by reindex_relation).
+	 * We only consider plain relations and materialized views here (toast
+	 * rels will be processed indirectly by reindex_relation).
 	 */
 	relationRelation = heap_open(RelationRelationId, AccessShareLock);
 	scan = heap_beginscan_catalog(relationRelation, 0, NULL);
diff --git a/src/backend/commands/seclabel.c b/src/backend/commands/seclabel.c
index 7466e664654edba353b99d09b5fbeff861185960..eaf0d0dabad89e1354bf61e7f7782ca04ce5e59c 100644
--- a/src/backend/commands/seclabel.c
+++ b/src/backend/commands/seclabel.c
@@ -111,7 +111,7 @@ ExecSecLabelStmt(SecLabelStmt *stmt)
 				relation->rd_rel->relkind != RELKIND_FOREIGN_TABLE)
 				ereport(ERROR,
 						(errcode(ERRCODE_WRONG_OBJECT_TYPE),
-						 errmsg("\"%s\" is not a table, view, composite type, or foreign table",
+						 errmsg("\"%s\" is not a table, view, materialized view, composite type, or foreign table",
 								RelationGetRelationName(relation))));
 			break;
 		default:
diff --git a/src/backend/commands/tablecmds.c b/src/backend/commands/tablecmds.c
index 6708725d696da5f0391600ff099888e2cc972550..f56ef28e229a8cc7ada9e69cda3b60a6f85fdf59 100644
--- a/src/backend/commands/tablecmds.c
+++ b/src/backend/commands/tablecmds.c
@@ -10696,7 +10696,7 @@ RangeVarCallbackForAlterRelation(const RangeVar *rv, Oid relid, Oid oldrelid,
 		relkind != RELKIND_FOREIGN_TABLE)
 		ereport(ERROR,
 				(errcode(ERRCODE_WRONG_OBJECT_TYPE),
-			errmsg("\"%s\" is not a table, view, sequence, or foreign table",
+			errmsg("\"%s\" is not a table, view, materialized view, sequence, or foreign table",
 				   rv->relname)));
 
 	ReleaseSysCache(tuple);
diff --git a/src/backend/commands/typecmds.c b/src/backend/commands/typecmds.c
index 031433d4bbb9606967e080c254408f6aef1ada6f..d4a14cabff28ac9949ad0f274760503654cc5d3f 100644
--- a/src/backend/commands/typecmds.c
+++ b/src/backend/commands/typecmds.c
@@ -2820,7 +2820,14 @@ get_rels_with_domain(Oid domainOid, LOCKMODE lockmode)
 												 NULL,
 												 format_type_be(domainOid));
 
-			/* Otherwise we can ignore views, composite types, etc */
+			/*
+			 * Otherwise, we can ignore relations except those with both
+			 * storage and user-chosen column types.
+			 *
+			 * XXX If an index-only scan could satisfy "col::some_domain" from
+			 * a suitable expression index, this should also check expression
+			 * index columns.
+			 */
 			if (rel->rd_rel->relkind != RELKIND_RELATION &&
 				rel->rd_rel->relkind != RELKIND_MATVIEW)
 			{
diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c
index 68fc9c6bae958dcce2cff7cc92746e4f0e058406..2f2c6acb968d598e1aed55972ea86bb773c818de 100644
--- a/src/backend/commands/vacuum.c
+++ b/src/backend/commands/vacuum.c
@@ -742,8 +742,8 @@ vac_update_datfrozenxid(void)
 		Form_pg_class classForm = (Form_pg_class) GETSTRUCT(classTup);
 
 		/*
-		 * Only consider heap and TOAST tables (anything else should have
-		 * InvalidTransactionId in relfrozenxid anyway.)
+		 * Only consider relations able to hold unfrozen XIDs (anything else
+		 * should have InvalidTransactionId in relfrozenxid anyway.)
 		 */
 		if (classForm->relkind != RELKIND_RELATION &&
 			classForm->relkind != RELKIND_MATVIEW &&
@@ -1044,7 +1044,7 @@ vacuum_rel(Oid relid, VacuumStmt *vacstmt, bool do_toast, bool for_wraparound)
 	}
 
 	/*
-	 * Check that it's a vacuumable table; we used to do this in
+	 * Check that it's a vacuumable relation; we used to do this in
 	 * get_rel_oids() but seems safer to check after we've locked the
 	 * relation.
 	 */
diff --git a/src/backend/parser/parse_utilcmd.c b/src/backend/parser/parse_utilcmd.c
index 40e3717b75de3ce5f09f9aa5f1d551779a9b21d7..ac662549e90979abad55160bded296e8e271cca4 100644
--- a/src/backend/parser/parse_utilcmd.c
+++ b/src/backend/parser/parse_utilcmd.c
@@ -683,7 +683,7 @@ transformTableLikeClause(CreateStmtContext *cxt, TableLikeClause *table_like_cla
 		relation->rd_rel->relkind != RELKIND_FOREIGN_TABLE)
 		ereport(ERROR,
 				(errcode(ERRCODE_WRONG_OBJECT_TYPE),
-				 errmsg("\"%s\" is not a table, view, composite type, or foreign table",
+				 errmsg("\"%s\" is not a table, view, materialized view, composite type, or foreign table",
 						RelationGetRelationName(relation))));
 
 	cancel_parser_errposition_callback(&pcbstate);
diff --git a/src/backend/rewrite/rewriteDefine.c b/src/backend/rewrite/rewriteDefine.c
index 92396b39bd38dca9073ffd0df131aa31b3243909..0e9f515a09c8a74f79fba8ee47a436f8d81c31ca 100644
--- a/src/backend/rewrite/rewriteDefine.c
+++ b/src/backend/rewrite/rewriteDefine.c
@@ -258,6 +258,8 @@ DefineQueryRewrite(char *rulename,
 
 	/*
 	 * Verify relation is of a type that rules can sensibly be applied to.
+	 * Internal callers can target materialized views, but transformRuleStmt()
+	 * blocks them for users.  Don't mention them in the error message.
 	 */
 	if (event_relation->rd_rel->relkind != RELKIND_RELATION &&
 		event_relation->rd_rel->relkind != RELKIND_MATVIEW &&
diff --git a/src/bin/pg_dump/common.c b/src/bin/pg_dump/common.c
index 58322dc59a6429bfe2134d07d142d6e703dfd4d9..247ad92ab2e01cff24c4eb49dc9814a731d0f7d7 100644
--- a/src/bin/pg_dump/common.c
+++ b/src/bin/pg_dump/common.c
@@ -269,7 +269,7 @@ flagInhTables(TableInfo *tblinfo, int numTables,
 
 	for (i = 0; i < numTables; i++)
 	{
-		/* Sequences and views never have parents */
+		/* Some kinds never have parents */
 		if (tblinfo[i].relkind == RELKIND_SEQUENCE ||
 			tblinfo[i].relkind == RELKIND_VIEW ||
 			tblinfo[i].relkind == RELKIND_MATVIEW)
@@ -315,7 +315,7 @@ flagInhAttrs(TableInfo *tblinfo, int numTables)
 		int			numParents;
 		TableInfo **parents;
 
-		/* Sequences and views never have parents */
+		/* Some kinds never have parents */
 		if (tbinfo->relkind == RELKIND_SEQUENCE ||
 			tbinfo->relkind == RELKIND_VIEW ||
 			tbinfo->relkind == RELKIND_MATVIEW)
diff --git a/src/pl/tcl/pltcl.c b/src/pl/tcl/pltcl.c
index 4cd59bc3ea6eefb43eb5775bc6a1d1533fea6010..c94d0d8075314d5039f1b40373ee0b139408e2cc 100644
--- a/src/pl/tcl/pltcl.c
+++ b/src/pl/tcl/pltcl.c
@@ -504,7 +504,7 @@ pltcl_init_load_unknown(Tcl_Interp *interp)
 									 AccessShareLock, true);
 	if (pmrel == NULL)
 		return;
-	/* must be table or view, else ignore */
+	/* sanity-check the relation kind */
 	if (!(pmrel->rd_rel->relkind == RELKIND_RELATION ||
 		  pmrel->rd_rel->relkind == RELKIND_MATVIEW ||
 		  pmrel->rd_rel->relkind == RELKIND_VIEW))
diff --git a/src/test/regress/expected/create_table_like.out b/src/test/regress/expected/create_table_like.out
index 3c6b585e60db5acdcfc9a597643c8c165fa0cb7b..5f29b3978dd24e9a9f6ad91fabbbf63a4a7ede62 100644
--- a/src/test/regress/expected/create_table_like.out
+++ b/src/test/regress/expected/create_table_like.out
@@ -221,7 +221,7 @@ NOTICE:  drop cascades to table inhe
 CREATE TABLE ctlt4 (a int, b text);
 CREATE SEQUENCE ctlseq1;
 CREATE TABLE ctlt10 (LIKE ctlseq1);  -- fail
-ERROR:  "ctlseq1" is not a table, view, composite type, or foreign table
+ERROR:  "ctlseq1" is not a table, view, materialized view, composite type, or foreign table
 LINE 1: CREATE TABLE ctlt10 (LIKE ctlseq1);
                                   ^
 CREATE VIEW ctlv1 AS SELECT * FROM ctlt4;