diff --git a/src/backend/optimizer/plan/setrefs.c b/src/backend/optimizer/plan/setrefs.c
index dd2b9ed..e7ddc14 100644
--- a/src/backend/optimizer/plan/setrefs.c
+++ b/src/backend/optimizer/plan/setrefs.c
@@ -16,7 +16,9 @@
 #include "postgres.h"
 
 #include "access/transam.h"
+#include "catalog/pg_class.h"
 #include "catalog/pg_type.h"
+#include "foreign/foreign.h"
 #include "nodes/makefuncs.h"
 #include "nodes/nodeFuncs.h"
 #include "optimizer/pathnode.h"
@@ -150,6 +152,12 @@ static List *set_returning_clause_references(PlannerInfo *root,
 static bool fix_opfuncids_walker(Node *node, void *context);
 static bool extract_query_dependencies_walker(Node *node,
 								  PlannerInfo *context);
+static void record_plan_foreign_table_dependency(PlannerInfo *root,
+								  Oid ftid);
+static void record_plan_foreign_data_wrapper_dependency(PlannerInfo *root,
+								  Oid fdwid);
+static void record_plan_foreign_server_dependency(PlannerInfo *root,
+								  Oid serverid);
 
 /*****************************************************************************
  *
@@ -2652,6 +2660,54 @@ record_plan_function_dependency(PlannerInfo *root, Oid funcid)
 }
 
 /*
+ * record_plan_foreign_table_dependency
+ *		Mark the current plan as depending on a particular foreign table.
+ */
+static void
+record_plan_foreign_table_dependency(PlannerInfo *root, Oid ftid)
+{
+	PlanInvalItem *inval_item = makeNode(PlanInvalItem);
+
+	inval_item->cacheId = FOREIGNTABLEREL;
+	inval_item->hashValue = GetSysCacheHashValue1(FOREIGNTABLEREL,
+												   ObjectIdGetDatum(ftid));
+
+	root->glob->invalItems = lappend(root->glob->invalItems, inval_item);
+}
+
+/*
+ * record_plan_foreign_data_wrapper_dependency
+ *		Mark the current plan as depending on a particular FDW.
+ */
+static void
+record_plan_foreign_data_wrapper_dependency(PlannerInfo *root, Oid fdwid)
+{
+	PlanInvalItem *inval_item = makeNode(PlanInvalItem);
+
+	inval_item->cacheId = FOREIGNDATAWRAPPEROID;
+	inval_item->hashValue = GetSysCacheHashValue1(FOREIGNDATAWRAPPEROID,
+												   ObjectIdGetDatum(fdwid));
+
+	root->glob->invalItems = lappend(root->glob->invalItems, inval_item);
+}
+
+/*
+ * record_plan_foreign_server_dependency
+ *		Mark the current plan as depending on a particular FDW.
+ */
+static void
+record_plan_foreign_server_dependency(PlannerInfo *root, Oid serverid)
+{
+	PlanInvalItem *inval_item = makeNode(PlanInvalItem);
+
+	inval_item->cacheId = FOREIGNSERVEROID;
+	inval_item->hashValue = GetSysCacheHashValue1(FOREIGNSERVEROID,
+												   ObjectIdGetDatum(serverid));
+
+	root->glob->invalItems = lappend(root->glob->invalItems, inval_item);
+}
+
+/*
  * extract_query_dependencies
  *		Given a not-yet-planned query or queries (i.e. a Query node or list
  *		of Query nodes), extract dependencies just as set_plan_references
@@ -2723,6 +2779,22 @@ extract_query_dependencies_walker(Node *node, PlannerInfo *context)
 			if (rte->rtekind == RTE_RELATION)
 				context->glob->relationOids =
 					lappend_oid(context->glob->relationOids, rte->relid);
+
+			if (rte->relkind == RELKIND_FOREIGN_TABLE)
+			{
+				ForeignTable   *ftable;
+				ForeignServer  *fserver;
+
+				ftable = GetForeignTable(rte->relid);
+				fserver = GetForeignServer(ftable->serverid);
+
+				record_plan_foreign_table_dependency(context,
+													 ftable->relid);
+				record_plan_foreign_server_dependency(context,
+													  ftable->serverid);
+				record_plan_foreign_data_wrapper_dependency(context,
+															fserver->fdwid);
+			}
 		}
 
 		/* And recurse into the query's subexpressions */
diff --git a/src/backend/utils/cache/plancache.c b/src/backend/utils/cache/plancache.c
index 8fd9f2b..a1af0c1 100644
--- a/src/backend/utils/cache/plancache.c
+++ b/src/backend/utils/cache/plancache.c
@@ -124,6 +124,10 @@ InitPlanCache(void)
 	CacheRegisterSyscacheCallback(AMOPOPID, PlanCacheSysCallback, (Datum) 0);
 	/* User mapping change may invalidate plans with pushed down foreign join */
 	CacheRegisterSyscacheCallback(USERMAPPINGOID, PlanCacheUserMappingCallback, (Datum) 0);
+	/* Foreign table/data wrapper/server alterations invalidate any related plans */
+	CacheRegisterSyscacheCallback(FOREIGNTABLEREL, PlanCacheFuncCallback, (Datum) 0);
+	CacheRegisterSyscacheCallback(FOREIGNDATAWRAPPEROID, PlanCacheFuncCallback, (Datum) 0);
+	CacheRegisterSyscacheCallback(FOREIGNSERVEROID, PlanCacheFuncCallback, (Datum) 0);
 }
 
 /*
