diff --git a/src/init.cpp b/src/init.cpp
--- a/src/init.cpp
+++ b/src/init.cpp
@@ -319,7 +319,6 @@
     node.chain_clients.clear();
     UnregisterAllValidationInterfaces();
     GetMainSignals().UnregisterBackgroundSignalScheduler();
-    GetMainSignals().UnregisterWithMempoolSignals(g_mempool);
     globalVerifyHandle.reset();
     ECC_Stop();
     if (node.mempool) {
@@ -2122,7 +2121,6 @@
         60000);
 
     GetMainSignals().RegisterBackgroundSignalScheduler(scheduler);
-    GetMainSignals().RegisterWithMempoolSignals(g_mempool);
 
     // Create client interfaces for wallets that are supposed to be loaded
     // according to -wallet and -disablewallet options. This only constructs
diff --git a/src/test/policyestimator_tests.cpp b/src/test/policyestimator_tests.cpp
--- a/src/test/policyestimator_tests.cpp
+++ b/src/test/policyestimator_tests.cpp
@@ -14,7 +14,7 @@
 
 #include <boost/test/unit_test.hpp>
 
-BOOST_FIXTURE_TEST_SUITE(policyestimator_tests, BasicTestingSetup)
+BOOST_FIXTURE_TEST_SUITE(policyestimator_tests, TestingSetup)
 
 BOOST_AUTO_TEST_CASE(MempoolMinimumFeeEstimate) {
     CTxMemPool mpool;
@@ -85,15 +85,13 @@
                                .FromTx(tx));
     }
 
-    // Trim to size.  GetMinFee should be more than 10000 *
-    // DEFAULT_BLOCK_MIN_TX_FEE_PER_KB But the estimateFee should be
+    // Trim to size. GetMinFee should be more than 10000 *
+    // DEFAULT_BLOCK_MIN_TX_FEE_PER_KB, but the estimateFee should remain
     // unchanged.
     mpool.TrimToSize(1);
-
     BOOST_CHECK(mpool.GetMinFee(1) >=
                 CFeeRate(10000 * DEFAULT_BLOCK_MIN_TX_FEE_PER_KB,
                          CTransaction(tx).GetTotalSize()));
-
     BOOST_CHECK_MESSAGE(mpool.estimateFee() == mpool.GetMinFee(1),
                         "Confirm blocks has failed");
 }
diff --git a/src/txmempool.cpp b/src/txmempool.cpp
--- a/src/txmempool.cpp
+++ b/src/txmempool.cpp
@@ -20,6 +20,7 @@
 #include <util/system.h>
 #include <util/time.h>
 #include <validation.h>
+#include <validationinterface.h>
 #include <version.h>
 
 #include <algorithm>
@@ -463,6 +464,13 @@
 }
 
 void CTxMemPool::removeUnchecked(txiter it, MemPoolRemovalReason reason) {
+    CTransactionRef ptx = it->GetSharedTx();
+    NotifyEntryRemoved(ptx, reason);
+    if (reason != MemPoolRemovalReason::BLOCK &&
+        reason != MemPoolRemovalReason::CONFLICT) {
+        GetMainSignals().TransactionRemovedFromMempool(ptx);
+    }
+
     NotifyEntryRemoved(it->GetSharedTx(), reason);
     for (const CTxIn &txin : it->GetTx().vin) {
         mapNextTx.erase(txin.prevout);
diff --git a/src/validationinterface.h b/src/validationinterface.h
--- a/src/validationinterface.h
+++ b/src/validationinterface.h
@@ -23,8 +23,6 @@
 class CValidationState;
 class uint256;
 class CScheduler;
-class CTxMemPool;
-enum class MemPoolRemovalReason;
 
 // These functions dispatch to one or all registered wallets
 
@@ -171,8 +169,6 @@
     friend void ::CallFunctionInValidationInterfaceQueue(
         std::function<void()> func);
 
-    void MempoolEntryRemoved(CTransactionRef tx, MemPoolRemovalReason reason);
-
 public:
     /**
      * Register a CScheduler to give callbacks which should run in the
@@ -189,14 +185,10 @@
 
     size_t CallbacksPending();
 
-    /** Register with mempool to call TransactionRemovedFromMempool callbacks */
-    void RegisterWithMempoolSignals(CTxMemPool &pool);
-    /** Unregister with mempool */
-    void UnregisterWithMempoolSignals(CTxMemPool &pool);
-
     void UpdatedBlockTip(const CBlockIndex *, const CBlockIndex *,
                          bool fInitialDownload);
     void TransactionAddedToMempool(const CTransactionRef &);
+    void TransactionRemovedFromMempool(const CTransactionRef &);
     void
     BlockConnected(const std::shared_ptr<const CBlock> &,
                    const CBlockIndex *pindex,
diff --git a/src/validationinterface.cpp b/src/validationinterface.cpp
--- a/src/validationinterface.cpp
+++ b/src/validationinterface.cpp
@@ -5,13 +5,14 @@
 
 #include <validationinterface.h>
 
+#include <primitives/block.h>
 #include <scheduler.h>
-#include <txmempool.h>
 
 #include <atomic>
 #include <future>
 #include <list>
 #include <tuple>
+#include <unordered_map>
 #include <utility>
 
 #include <boost/signals2/signal.hpp>
@@ -61,13 +62,6 @@
 
 static CMainSignals g_signals;
 
-// This map has to be a separate global instead of a member of
-// MainSignalsInstance, because RegisterWithMempoolSignals is currently called
-// before RegisterBackgroundSignalScheduler, so MainSignalsInstance hasn't been
-// created yet.
-static std::unordered_map<CTxMemPool *, boost::signals2::scoped_connection>
-    g_connNotifyEntryRemoved;
-
 void CMainSignals::RegisterBackgroundSignalScheduler(CScheduler &scheduler) {
     assert(!m_internals);
     m_internals.reset(new MainSignalsInstance(&scheduler));
@@ -90,18 +84,6 @@
     return m_internals->m_schedulerClient.CallbacksPending();
 }
 
-void CMainSignals::RegisterWithMempoolSignals(CTxMemPool &pool) {
-    g_connNotifyEntryRemoved.emplace(
-        std::piecewise_construct, std::forward_as_tuple(&pool),
-        std::forward_as_tuple(pool.NotifyEntryRemoved.connect(
-            std::bind(&CMainSignals::MempoolEntryRemoved, this,
-                      std::placeholders::_1, std::placeholders::_2))));
-}
-
-void CMainSignals::UnregisterWithMempoolSignals(CTxMemPool &pool) {
-    g_connNotifyEntryRemoved.erase(&pool);
-}
-
 CMainSignals &GetMainSignals() {
     return g_signals;
 }
@@ -164,15 +146,6 @@
     promise.get_future().wait();
 }
 
-void CMainSignals::MempoolEntryRemoved(CTransactionRef ptx,
-                                       MemPoolRemovalReason reason) {
-    if (reason != MemPoolRemovalReason::BLOCK &&
-        reason != MemPoolRemovalReason::CONFLICT) {
-        m_internals->m_schedulerClient.AddToProcessQueue(
-            [ptx, this] { m_internals->TransactionRemovedFromMempool(ptx); });
-    }
-}
-
 void CMainSignals::UpdatedBlockTip(const CBlockIndex *pindexNew,
                                    const CBlockIndex *pindexFork,
                                    bool fInitialDownload) {
@@ -192,6 +165,11 @@
         [ptx, this] { m_internals->TransactionAddedToMempool(ptx); });
 }
 
+void CMainSignals::TransactionRemovedFromMempool(const CTransactionRef &ptx) {
+    m_internals->m_schedulerClient.AddToProcessQueue(
+        [ptx, this] { m_internals->TransactionRemovedFromMempool(ptx); });
+}
+
 void CMainSignals::BlockConnected(
     const std::shared_ptr<const CBlock> &pblock, const CBlockIndex *pindex,
     const std::shared_ptr<const std::vector<CTransactionRef>> &pvtxConflicted) {
diff --git a/test/lint/lint-circular-dependencies.sh b/test/lint/lint-circular-dependencies.sh
--- a/test/lint/lint-circular-dependencies.sh
+++ b/test/lint/lint-circular-dependencies.sh
@@ -26,7 +26,6 @@
     "wallet/rpcwallet -> wallet/wallet -> wallet/rpcwallet"
     "wallet/wallet -> wallet/walletdb -> wallet/wallet"
     "wallet/ismine -> wallet/wallet -> wallet/ismine"
-    "txmempool -> validation -> validationinterface -> txmempool"
     "avalanche -> validation -> avalanche"
     "chainparams -> protocol -> chainparams"
     "chainparamsbase -> util/system -> chainparamsbase"