diff --git a/src/backend/replication/logical/worker.c b/src/backend/replication/logical/worker.c
index 1432554d5a..01c1bd14f6 100644
--- a/src/backend/replication/logical/worker.c
+++ b/src/backend/replication/logical/worker.c
@@ -394,9 +394,6 @@ create_estate_for_relation(LogicalRepRelMapEntry *rel,
 static void
 finish_estate(EState *estate)
 {
-	/* Handle any queued AFTER triggers. */
-	AfterTriggerEndQuery(estate);
-
 	/* Cleanup. */
 	ExecResetTupleTable(estate->es_tupleTable, false);
 	FreeExecutorState(estate);
@@ -1226,9 +1223,14 @@ apply_handle_insert(StringInfo s)
 		apply_handle_tuple_routing(resultRelInfo, estate,
 								   remoteslot, NULL, rel, CMD_INSERT);
 	else
+	{
 		apply_handle_insert_internal(resultRelInfo, estate,
 									 remoteslot);
 
+		/* Handle any queued AFTER triggers */
+		AfterTriggerEndQuery(estate);
+	}
+
 	PopActiveSnapshot();
 
 	finish_estate(estate);
@@ -1371,9 +1373,14 @@ apply_handle_update(StringInfo s)
 		apply_handle_tuple_routing(resultRelInfo, estate,
 								   remoteslot, &newtup, rel, CMD_UPDATE);
 	else
+	{
 		apply_handle_update_internal(resultRelInfo, estate,
 									 remoteslot, &newtup, rel);
 
+		/* Handle any queued AFTER triggers */
+		AfterTriggerEndQuery(estate);
+	}
+
 	PopActiveSnapshot();
 
 	finish_estate(estate);
@@ -1494,9 +1501,14 @@ apply_handle_delete(StringInfo s)
 		apply_handle_tuple_routing(resultRelInfo, estate,
 								   remoteslot, NULL, rel, CMD_DELETE);
 	else
+	{
 		apply_handle_delete_internal(resultRelInfo, estate,
 									 remoteslot, &rel->remoterel);
 
+		/* Handle any queued AFTER triggers */
+		AfterTriggerEndQuery(estate);
+	}
+
 	PopActiveSnapshot();
 
 	finish_estate(estate);
@@ -1798,6 +1810,12 @@ apply_handle_tuple_routing(ResultRelInfo *relinfo,
 			break;
 	}
 
+	/*
+	 * Handle any queued AFTER triggers.  Note that this needs to be done
+	 * before closing any references to the relation used for tuple routing.
+	 */
+	AfterTriggerEndQuery(estate);
+
 	ExecCleanupTupleRouting(mtstate, proute);
 }
 
