 src/backend/catalog/genbki.pl  | 26 ++++++++++++++++++++++++++
 src/include/catalog/toasting.h | 32 ++------------------------------
 2 files changed, 28 insertions(+), 30 deletions(-)

diff --git a/src/backend/catalog/genbki.pl b/src/backend/catalog/genbki.pl
index edc8ea9f53..f4d7160c6a 100644
--- a/src/backend/catalog/genbki.pl
+++ b/src/backend/catalog/genbki.pl
@@ -285,6 +285,7 @@ my @tables_needing_macros;
 foreach my $catname (@catnames)
 {
 	my $catalog = $catalogs{$catname};
+	my $has_toastable_type = 0;
 
 	# Create one definition header with macro definitions for each catalog.
 	my $def_file = $output_path . $catname . '_d.h';
@@ -345,6 +346,12 @@ EOM
 		# Build hash of column names for use later
 		$attnames{$attname} = 1;
 
+		# Flag catalogs with toastable datatypes.
+		if ($types{$atttype}->{typstorage} eq 'x')
+		{
+			$has_toastable_type = 1;
+		}
+
 		# Emit column definitions
 		if (!$first)
 		{
@@ -506,6 +513,25 @@ EOM
 		}
 	}
 
+	# Create toast declarations for normal catalogs.  To prevent
+	# circular dependencies and to avoid adding complexity to VACUUM
+	# FULL logic, exclude pg_class, pg_attribute, and pg_index.  Also,
+	# to prevent pg_upgrade from seeing a non-empty new cluster, exclude
+	# pg_largeobject and pg_largeobject_metadata from the set as large
+	# object data is handled as user data.  Those relations have no reason
+	# to use a toast table anyway.  Toast tables and indexes for shared
+	# catalogs need stable oids, so must be specified in toasting.h.
+	if ($has_toastable_type and !$catalog->{shared_relation}
+		and $catname ne 'pg_class'
+		and $catname ne 'pg_attribute'
+		and $catname ne 'pg_index'
+		and $catname ne 'pg_largeobject'
+		and $catname ne 'pg_largeobject_metadata')
+	{
+		push @toast_decls, sprintf "declare toast %s %s on %s\n",
+		  $maxoid++, $maxoid++, $catname;
+	}
+
 	print $bki "close $catname\n";
 	printf $def "\n#endif\t\t\t\t\t\t\t/* %s_D_H */\n", uc $catname;
 
diff --git a/src/include/catalog/toasting.h b/src/include/catalog/toasting.h
index f259890e43..1c389c685d 100644
--- a/src/include/catalog/toasting.h
+++ b/src/include/catalog/toasting.h
@@ -42,37 +42,9 @@ extern void BootstrapToastTable(char *relName,
  * the OID to assign to the toast table, and the OID to assign to the
  * toast table's index.  The reason we hard-wire these OIDs is that we
  * need stable OIDs for shared relations, and that includes toast tables
- * of shared relations.
+ * of shared relations.  Toast table commands for normal catalogs are
+ * generated by genbki.pl, and oids for those are assigned on the fly.
  */
-
-/* normal catalogs */
-DECLARE_TOAST(pg_aggregate, 4159, 4160);
-DECLARE_TOAST(pg_attrdef, 2830, 2831);
-DECLARE_TOAST(pg_collation, 4161, 4162);
-DECLARE_TOAST(pg_constraint, 2832, 2833);
-DECLARE_TOAST(pg_default_acl, 4143, 4144);
-DECLARE_TOAST(pg_description, 2834, 2835);
-DECLARE_TOAST(pg_event_trigger, 4145, 4146);
-DECLARE_TOAST(pg_extension, 4147, 4148);
-DECLARE_TOAST(pg_foreign_data_wrapper, 4149, 4150);
-DECLARE_TOAST(pg_foreign_server, 4151, 4152);
-DECLARE_TOAST(pg_foreign_table, 4153, 4154);
-DECLARE_TOAST(pg_init_privs, 4155, 4156);
-DECLARE_TOAST(pg_language, 4157, 4158);
-DECLARE_TOAST(pg_namespace, 4163, 4164);
-DECLARE_TOAST(pg_partitioned_table, 4165, 4166);
-DECLARE_TOAST(pg_policy, 4167, 4168);
-DECLARE_TOAST(pg_proc, 2836, 2837);
-DECLARE_TOAST(pg_rewrite, 2838, 2839);
-DECLARE_TOAST(pg_seclabel, 3598, 3599);
-DECLARE_TOAST(pg_statistic, 2840, 2841);
-DECLARE_TOAST(pg_statistic_ext, 3439, 3440);
-DECLARE_TOAST(pg_trigger, 2336, 2337);
-DECLARE_TOAST(pg_ts_dict, 4169, 4170);
-DECLARE_TOAST(pg_type, 4171, 4172);
-DECLARE_TOAST(pg_user_mapping, 4173, 4174);
-
-/* shared catalogs */
 DECLARE_TOAST(pg_authid, 4175, 4176);
 #define PgAuthidToastTable 4175
 #define PgAuthidToastIndex 4176
