diff --git a/src/backend/utils/cache/inval.c b/src/backend/utils/cache/inval.c
index 80d7a76e24..b9f698ef2c 100644
--- a/src/backend/utils/cache/inval.c
+++ b/src/backend/utils/cache/inval.c
@@ -52,10 +52,11 @@
  *	catcaches may need invalidation for a given tuple.
  *
  *	Also, whenever we see an operation on a pg_class, pg_attribute, or
  *	pg_index tuple, we register a relcache flush operation for the relation
  *	described by that tuple (as specified in CacheInvalidateHeapTuple()).
+ *	Likewise for pg_constraint tuples for foreign keys on relations.
  *
  *	We keep the relcache flush requests in lists separate from the catcache
  *	tuple flush requests.  This allows us to issue all the pending catcache
  *	flushes before we issue relcache flushes, which saves us from loading
  *	a catcache tuple during relcache load only to flush it again right away.
@@ -98,10 +99,11 @@
 #include <limits.h>
 
 #include "access/htup_details.h"
 #include "access/xact.h"
 #include "catalog/catalog.h"
+#include "catalog/pg_constraint.h"
 #include "miscadmin.h"
 #include "storage/sinval.h"
 #include "storage/smgr.h"
 #include "utils/catcache.h"
 #include "utils/inval.h"
@@ -1201,10 +1203,27 @@ CacheInvalidateHeapTuple(Relation relation,
 		 * shared catalogs can't have such updates.
 		 */
 		relationId = indextup->indexrelid;
 		databaseId = MyDatabaseId;
 	}
+	else if (tupleRelId == ConstraintRelationId)
+	{
+		Form_pg_constraint constrtup = (Form_pg_constraint) GETSTRUCT(tuple);
+
+		/*
+		 * Foreign keys are part of relcache entries, too, so send out an
+		 * inval for the table that the FK applies to.
+		 */
+		if (constrtup->contype == CONSTRAINT_FOREIGN &&
+			OidIsValid(constrtup->conrelid))
+		{
+			relationId = constrtup->conrelid;
+			databaseId = MyDatabaseId;
+		}
+		else
+			return;
+	}
 	else
 		return;
 
 	/*
 	 * Yes.  We need to register a relcache invalidation event.
