diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c
index b5fd30a4f95933ef414607ca831464065d8cc9d6..31941e99edbd76fb8baf85a6c749fe1194cdb917 100644
--- a/src/backend/access/common/reloptions.c
+++ b/src/backend/access/common/reloptions.c
@@ -61,6 +61,14 @@ static relopt_bool boolRelOpts[] =
 		},
 		true
 	},
+	{
+		{
+			"user_catalog_table",
+			"Declare a table as an additional catalog table, e.g. for the purpose of logical replication",
+			RELOPT_KIND_HEAP
+		},
+		false
+	},
 	{
 		{
 			"fastupdate",
@@ -1166,6 +1174,8 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind)
 		offsetof(StdRdOptions, security_barrier)},
 		{"check_option", RELOPT_TYPE_STRING,
 		offsetof(StdRdOptions, check_option_offset)},
+		{"user_catalog_table", RELOPT_TYPE_BOOL,
+		 offsetof(StdRdOptions, user_catalog_table)}
 	};
 
 	options = parseRelOptions(reloptions, validate, kind, &numoptions);
diff --git a/src/backend/commands/tablecmds.c b/src/backend/commands/tablecmds.c
index 1d9f29a7b7c18742cc3c2639e20c4ba4bd0763fe..b9cd88d57015416066c7f3db70d9c681708426ff 100644
--- a/src/backend/commands/tablecmds.c
+++ b/src/backend/commands/tablecmds.c
@@ -3532,6 +3532,12 @@ ATRewriteTables(List **wqueue, LOCKMODE lockmode)
 						 errmsg("cannot rewrite system relation \"%s\"",
 								RelationGetRelationName(OldHeap))));
 
+			if (RelationIsUsedAsCatalogTable(OldHeap))
+				ereport(ERROR,
+						(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
+						 errmsg("cannot rewrite table \"%s\" used as a catalog table",
+								RelationGetRelationName(OldHeap))));
+
 			/*
 			 * Don't allow rewrite on temp tables of other backends ... their
 			 * local buffer manager is not going to cope.
diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h
index ad878cf1a225b61c7fddb7016337cc09214aa8df..383744b3a0c350860dd054b206c5f652535d83b0 100644
--- a/src/include/utils/rel.h
+++ b/src/include/utils/rel.h
@@ -217,6 +217,7 @@ typedef struct StdRdOptions
 	AutoVacOpts autovacuum;		/* autovacuum-related options */
 	bool		security_barrier;		/* for views */
 	int			check_option_offset;	/* for views */
+	bool		user_catalog_table;		/* use as an additional catalog relation */
 } StdRdOptions;
 
 #define HEAP_MIN_FILLFACTOR			10
@@ -285,6 +286,15 @@ typedef struct StdRdOptions
 			((StdRdOptions *) (relation)->rd_options)->check_option_offset,	\
 			"cascaded") == 0 : false)
 
+/*
+ * RelationIsUsedAsCatalogTable
+ *		Returns whether the relation should be treated as a catalog table
+ *      from the pov of logical decoding.
+ */
+#define RelationIsUsedAsCatalogTable(relation)	\
+	((relation)->rd_options ?				\
+	 ((StdRdOptions *) (relation)->rd_options)->user_catalog_table : false)
+
 /*
  * RelationIsValid
  *		True iff relation descriptor is valid.
@@ -462,7 +472,7 @@ typedef struct StdRdOptions
 #define RelationIsAccessibleInLogicalDecoding(relation) \
 	(XLogLogicalInfoActive() && \
 	 RelationNeedsWAL(relation) && \
-	 IsCatalogRelation(relation))
+	 (IsCatalogRelation(relation) || RelationIsUsedAsCatalogTable(relation)))
 
 /*
  * RelationIsLogicallyLogged
@@ -471,7 +481,9 @@ typedef struct StdRdOptions
  *
  * We don't log information for unlogged tables (since they don't WAL log
  * anyway) and for system tables (their content is hard to make sense of, and
- * it would complicate decoding slightly for little gain).
+ * it would complicate decoding slightly for little gain). Note that we *do*
+ * log information for user defined catalog tables since they presumably are
+ * interesting to the user...
  */
 #define RelationIsLogicallyLogged(relation) \
 	(XLogLogicalInfoActive() && \