diff --git a/core/state/managed_state.go b/core/state/managed_state.go
deleted file mode 100644
index 1390ef4a00af4ccc155b05dc0753fb854e80d0b5..0000000000000000000000000000000000000000
--- a/core/state/managed_state.go
+++ /dev/null
@@ -1,143 +0,0 @@
-// Copyright 2015 The go-ethereum Authors
-// This file is part of the go-ethereum library.
-//
-// The go-ethereum library is free software: you can redistribute it and/or modify
-// it under the terms of the GNU Lesser General Public License as published by
-// the Free Software Foundation, either version 3 of the License, or
-// (at your option) any later version.
-//
-// The go-ethereum library is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU Lesser General Public License for more details.
-//
-// You should have received a copy of the GNU Lesser General Public License
-// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
-
-package state
-
-import (
-	"sync"
-
-	"github.com/ethereum/go-ethereum/common"
-)
-
-type account struct {
-	stateObject *stateObject
-	nstart      uint64
-	nonces      []bool
-}
-
-type ManagedState struct {
-	*StateDB
-
-	mu sync.RWMutex
-
-	accounts map[common.Address]*account
-}
-
-// ManagedState returns a new managed state with the statedb as it's backing layer
-func ManageState(statedb *StateDB) *ManagedState {
-	return &ManagedState{
-		StateDB:  statedb.Copy(),
-		accounts: make(map[common.Address]*account),
-	}
-}
-
-// SetState sets the backing layer of the managed state
-func (ms *ManagedState) SetState(statedb *StateDB) {
-	ms.mu.Lock()
-	defer ms.mu.Unlock()
-	ms.StateDB = statedb
-}
-
-// RemoveNonce removed the nonce from the managed state and all future pending nonces
-func (ms *ManagedState) RemoveNonce(addr common.Address, n uint64) {
-	if ms.hasAccount(addr) {
-		ms.mu.Lock()
-		defer ms.mu.Unlock()
-
-		account := ms.getAccount(addr)
-		if n-account.nstart <= uint64(len(account.nonces)) {
-			reslice := make([]bool, n-account.nstart)
-			copy(reslice, account.nonces[:n-account.nstart])
-			account.nonces = reslice
-		}
-	}
-}
-
-// NewNonce returns the new canonical nonce for the managed account
-func (ms *ManagedState) NewNonce(addr common.Address) uint64 {
-	ms.mu.Lock()
-	defer ms.mu.Unlock()
-
-	account := ms.getAccount(addr)
-	for i, nonce := range account.nonces {
-		if !nonce {
-			return account.nstart + uint64(i)
-		}
-	}
-	account.nonces = append(account.nonces, true)
-
-	return uint64(len(account.nonces)-1) + account.nstart
-}
-
-// GetNonce returns the canonical nonce for the managed or unmanaged account.
-//
-// Because GetNonce mutates the DB, we must take a write lock.
-func (ms *ManagedState) GetNonce(addr common.Address) uint64 {
-	ms.mu.Lock()
-	defer ms.mu.Unlock()
-
-	if ms.hasAccount(addr) {
-		account := ms.getAccount(addr)
-		return uint64(len(account.nonces)) + account.nstart
-	} else {
-		return ms.StateDB.GetNonce(addr)
-	}
-}
-
-// SetNonce sets the new canonical nonce for the managed state
-func (ms *ManagedState) SetNonce(addr common.Address, nonce uint64) {
-	ms.mu.Lock()
-	defer ms.mu.Unlock()
-
-	so := ms.GetOrNewStateObject(addr)
-	so.SetNonce(nonce)
-
-	ms.accounts[addr] = newAccount(so)
-}
-
-// HasAccount returns whether the given address is managed or not
-func (ms *ManagedState) HasAccount(addr common.Address) bool {
-	ms.mu.RLock()
-	defer ms.mu.RUnlock()
-	return ms.hasAccount(addr)
-}
-
-func (ms *ManagedState) hasAccount(addr common.Address) bool {
-	_, ok := ms.accounts[addr]
-	return ok
-}
-
-// populate the managed state
-func (ms *ManagedState) getAccount(addr common.Address) *account {
-	if account, ok := ms.accounts[addr]; !ok {
-		so := ms.GetOrNewStateObject(addr)
-		ms.accounts[addr] = newAccount(so)
-	} else {
-		// Always make sure the state account nonce isn't actually higher
-		// than the tracked one.
-		so := ms.StateDB.getStateObject(addr)
-		if so != nil && uint64(len(account.nonces))+account.nstart < so.Nonce() {
-			ms.accounts[addr] = newAccount(so)
-		}
-
-	}
-
-	return ms.accounts[addr]
-}
-
-func newAccount(so *stateObject) *account {
-	return &account{so, so.Nonce(), nil}
-}
diff --git a/core/state/managed_state_test.go b/core/state/managed_state_test.go
deleted file mode 100644
index fdfde96adfee33ae007443171f60eff0d0fb23cc..0000000000000000000000000000000000000000
--- a/core/state/managed_state_test.go
+++ /dev/null
@@ -1,123 +0,0 @@
-// Copyright 2015 The go-ethereum Authors
-// This file is part of the go-ethereum library.
-//
-// The go-ethereum library is free software: you can redistribute it and/or modify
-// it under the terms of the GNU Lesser General Public License as published by
-// the Free Software Foundation, either version 3 of the License, or
-// (at your option) any later version.
-//
-// The go-ethereum library is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU Lesser General Public License for more details.
-//
-// You should have received a copy of the GNU Lesser General Public License
-// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
-
-package state
-
-import (
-	"testing"
-
-	"github.com/ethereum/go-ethereum/common"
-	"github.com/ethereum/go-ethereum/core/rawdb"
-)
-
-var addr = common.BytesToAddress([]byte("test"))
-
-func create() (*ManagedState, *account) {
-	statedb, _ := New(common.Hash{}, NewDatabase(rawdb.NewMemoryDatabase()))
-	ms := ManageState(statedb)
-	ms.StateDB.SetNonce(addr, 100)
-	ms.accounts[addr] = newAccount(ms.StateDB.getStateObject(addr))
-	return ms, ms.accounts[addr]
-}
-
-func TestNewNonce(t *testing.T) {
-	ms, _ := create()
-
-	nonce := ms.NewNonce(addr)
-	if nonce != 100 {
-		t.Error("expected nonce 100. got", nonce)
-	}
-
-	nonce = ms.NewNonce(addr)
-	if nonce != 101 {
-		t.Error("expected nonce 101. got", nonce)
-	}
-}
-
-func TestRemove(t *testing.T) {
-	ms, account := create()
-
-	nn := make([]bool, 10)
-	for i := range nn {
-		nn[i] = true
-	}
-	account.nonces = append(account.nonces, nn...)
-
-	i := uint64(5)
-	ms.RemoveNonce(addr, account.nstart+i)
-	if len(account.nonces) != 5 {
-		t.Error("expected", i, "'th index to be false")
-	}
-}
-
-func TestReuse(t *testing.T) {
-	ms, account := create()
-
-	nn := make([]bool, 10)
-	for i := range nn {
-		nn[i] = true
-	}
-	account.nonces = append(account.nonces, nn...)
-
-	i := uint64(5)
-	ms.RemoveNonce(addr, account.nstart+i)
-	nonce := ms.NewNonce(addr)
-	if nonce != 105 {
-		t.Error("expected nonce to be 105. got", nonce)
-	}
-}
-
-func TestRemoteNonceChange(t *testing.T) {
-	ms, account := create()
-	nn := make([]bool, 10)
-	for i := range nn {
-		nn[i] = true
-	}
-	account.nonces = append(account.nonces, nn...)
-	ms.NewNonce(addr)
-
-	ms.StateDB.stateObjects[addr].data.Nonce = 200
-	nonce := ms.NewNonce(addr)
-	if nonce != 200 {
-		t.Error("expected nonce after remote update to be", 200, "got", nonce)
-	}
-	ms.NewNonce(addr)
-	ms.NewNonce(addr)
-	ms.NewNonce(addr)
-	ms.StateDB.stateObjects[addr].data.Nonce = 200
-	nonce = ms.NewNonce(addr)
-	if nonce != 204 {
-		t.Error("expected nonce after remote update to be", 204, "got", nonce)
-	}
-}
-
-func TestSetNonce(t *testing.T) {
-	ms, _ := create()
-
-	var addr common.Address
-	ms.SetNonce(addr, 10)
-
-	if ms.GetNonce(addr) != 10 {
-		t.Error("Expected nonce of 10, got", ms.GetNonce(addr))
-	}
-
-	addr[0] = 1
-	ms.StateDB.SetNonce(addr, 1)
-
-	if ms.GetNonce(addr) != 1 {
-		t.Error("Expected nonce of 1, got", ms.GetNonce(addr))
-	}
-}
diff --git a/core/tx_noncer.go b/core/tx_noncer.go
new file mode 100644
index 0000000000000000000000000000000000000000..98a78e087e2ad4f2a0c468167597aadbb06390ec
--- /dev/null
+++ b/core/tx_noncer.go
@@ -0,0 +1,53 @@
+// Copyright 2019 The go-ethereum Authors
+// This file is part of the go-ethereum library.
+//
+// The go-ethereum library is free software: you can redistribute it and/or modify
+// it under the terms of the GNU Lesser General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// The go-ethereum library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public License
+// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
+
+package core
+
+import (
+	"github.com/ethereum/go-ethereum/common"
+	"github.com/ethereum/go-ethereum/core/state"
+)
+
+// txNoncer is a tiny virtual state database to manage the executable nonces of
+// accounts in the pool, falling back to reading from a real state database if
+// an account is unknown.
+type txNoncer struct {
+	fallback *state.StateDB
+	nonces   map[common.Address]uint64
+}
+
+// newTxNoncer creates a new virtual state database to track the pool nonces.
+func newTxNoncer(statedb *state.StateDB) *txNoncer {
+	return &txNoncer{
+		fallback: statedb.Copy(),
+		nonces:   make(map[common.Address]uint64),
+	}
+}
+
+// get returns the current nonce of an account, falling back to a real state
+// database if the account is unknown.
+func (txn *txNoncer) get(addr common.Address) uint64 {
+	if _, ok := txn.nonces[addr]; !ok {
+		txn.nonces[addr] = txn.fallback.GetNonce(addr)
+	}
+	return txn.nonces[addr]
+}
+
+// set inserts a new virtual nonce into the virtual state database to be returned
+// whenever the pool requests it instead of reaching into the real state database.
+func (txn *txNoncer) set(addr common.Address, nonce uint64) {
+	txn.nonces[addr] = nonce
+}
diff --git a/core/tx_pool.go b/core/tx_pool.go
index 5d37fcffc085b8ca5f5c5ef0afd5af21591ed250..43caf16b18eda41329433460e6f9b93d5cfc59dc 100644
--- a/core/tx_pool.go
+++ b/core/tx_pool.go
@@ -217,9 +217,9 @@ type TxPool struct {
 	signer      types.Signer
 	mu          sync.RWMutex
 
-	currentState  *state.StateDB      // Current state in the blockchain head
-	pendingState  *state.ManagedState // Pending state tracking virtual nonces
-	currentMaxGas uint64              // Current gas limit for transaction caps
+	currentState  *state.StateDB // Current state in the blockchain head
+	pendingNonces *txNoncer      // Pending state tracking virtual nonces
+	currentMaxGas uint64         // Current gas limit for transaction caps
 
 	locals  *accountSet // Set of local transaction to exempt from eviction rules
 	journal *txJournal  // Journal of local transaction to back up to disk
@@ -417,12 +417,13 @@ func (pool *TxPool) SetGasPrice(price *big.Int) {
 	log.Info("Transaction pool price threshold updated", "price", price)
 }
 
-// State returns the virtual managed state of the transaction pool.
-func (pool *TxPool) State() *state.ManagedState {
+// Nonce returns the next nonce of an account, with all transactions executable
+// by the pool already applied on top.
+func (pool *TxPool) Nonce(addr common.Address) uint64 {
 	pool.mu.RLock()
 	defer pool.mu.RUnlock()
 
-	return pool.pendingState
+	return pool.pendingNonces.get(addr)
 }
 
 // Stats retrieves the current pool stats, namely the number of pending and the
@@ -713,7 +714,7 @@ func (pool *TxPool) promoteTx(addr common.Address, hash common.Hash, tx *types.T
 	}
 	// Set the potentially new pending nonce and notify any subsystems of the new tx
 	pool.beats[addr] = time.Now()
-	pool.pendingState.SetNonce(addr, tx.Nonce()+1)
+	pool.pendingNonces.set(addr, tx.Nonce()+1)
 
 	return true
 }
@@ -853,8 +854,8 @@ func (pool *TxPool) removeTx(hash common.Hash, outofbound bool) {
 				pool.enqueueTx(tx.Hash(), tx)
 			}
 			// Update the account nonce if needed
-			if nonce := tx.Nonce(); pool.pendingState.GetNonce(addr) > nonce {
-				pool.pendingState.SetNonce(addr, nonce)
+			if nonce := tx.Nonce(); pool.pendingNonces.get(addr) > nonce {
+				pool.pendingNonces.set(addr, nonce)
 			}
 			// Reduce the pending counter
 			pendingCounter.Dec(int64(1 + len(invalids)))
@@ -990,7 +991,7 @@ func (pool *TxPool) runReorg(done chan struct{}, reset *txpoolResetRequest, dirt
 
 		// Nonces were reset, discard any events that became stale
 		for addr := range events {
-			events[addr].Forward(pool.pendingState.GetNonce(addr))
+			events[addr].Forward(pool.pendingNonces.get(addr))
 			if events[addr].Len() == 0 {
 				delete(events, addr)
 			}
@@ -1023,7 +1024,7 @@ func (pool *TxPool) runReorg(done chan struct{}, reset *txpoolResetRequest, dirt
 	// Update all accounts to the latest known pending nonce
 	for addr, list := range pool.pending {
 		txs := list.Flatten() // Heavy but will be cached and is needed by the miner anyway
-		pool.pendingState.SetNonce(addr, txs[len(txs)-1].Nonce()+1)
+		pool.pendingNonces.set(addr, txs[len(txs)-1].Nonce()+1)
 	}
 	pool.mu.Unlock()
 
@@ -1112,7 +1113,7 @@ func (pool *TxPool) reset(oldHead, newHead *types.Header) {
 		return
 	}
 	pool.currentState = statedb
-	pool.pendingState = state.ManageState(statedb)
+	pool.pendingNonces = newTxNoncer(statedb)
 	pool.currentMaxGas = newHead.GasLimit
 
 	// Inject any transactions discarded due to reorgs
@@ -1151,7 +1152,7 @@ func (pool *TxPool) promoteExecutables(accounts []common.Address) []*types.Trans
 		queuedNofundsMeter.Mark(int64(len(drops)))
 
 		// Gather all executable transactions and promote them
-		readies := list.Ready(pool.pendingState.GetNonce(addr))
+		readies := list.Ready(pool.pendingNonces.get(addr))
 		for _, tx := range readies {
 			hash := tx.Hash()
 			if pool.promoteTx(addr, hash, tx) {
@@ -1231,8 +1232,8 @@ func (pool *TxPool) truncatePending() {
 						pool.all.Remove(hash)
 
 						// Update the account nonce to the dropped transaction
-						if nonce := tx.Nonce(); pool.pendingState.GetNonce(offenders[i]) > nonce {
-							pool.pendingState.SetNonce(offenders[i], nonce)
+						if nonce := tx.Nonce(); pool.pendingNonces.get(offenders[i]) > nonce {
+							pool.pendingNonces.set(offenders[i], nonce)
 						}
 						log.Trace("Removed fairness-exceeding pending transaction", "hash", hash)
 					}
@@ -1260,8 +1261,8 @@ func (pool *TxPool) truncatePending() {
 					pool.all.Remove(hash)
 
 					// Update the account nonce to the dropped transaction
-					if nonce := tx.Nonce(); pool.pendingState.GetNonce(addr) > nonce {
-						pool.pendingState.SetNonce(addr, nonce)
+					if nonce := tx.Nonce(); pool.pendingNonces.get(addr) > nonce {
+						pool.pendingNonces.set(addr, nonce)
 					}
 					log.Trace("Removed fairness-exceeding pending transaction", "hash", hash)
 				}
diff --git a/core/tx_pool_test.go b/core/tx_pool_test.go
index 7f1832a43f0cd4fe78815a2a020c978d16ad3304..7df1a2c6f9539fc2be53f822aa36f00a917ab7cd 100644
--- a/core/tx_pool_test.go
+++ b/core/tx_pool_test.go
@@ -109,7 +109,7 @@ func validateTxPoolInternals(pool *TxPool) error {
 				last = nonce
 			}
 		}
-		if nonce := pool.pendingState.GetNonce(addr); nonce != last+1 {
+		if nonce := pool.Nonce(addr); nonce != last+1 {
 			return fmt.Errorf("pending nonce mismatch: have %v, want %v", nonce, last+1)
 		}
 	}
@@ -195,14 +195,14 @@ func TestStateChangeDuringTransactionPoolReset(t *testing.T) {
 	pool := NewTxPool(testTxPoolConfig, params.TestChainConfig, blockchain)
 	defer pool.Stop()
 
-	nonce := pool.State().GetNonce(address)
+	nonce := pool.Nonce(address)
 	if nonce != 0 {
 		t.Fatalf("Invalid nonce, want 0, got %d", nonce)
 	}
 
 	pool.addRemotesSync([]*types.Transaction{tx0, tx1})
 
-	nonce = pool.State().GetNonce(address)
+	nonce = pool.Nonce(address)
 	if nonce != 2 {
 		t.Fatalf("Invalid nonce, want 2, got %d", nonce)
 	}
@@ -215,7 +215,7 @@ func TestStateChangeDuringTransactionPoolReset(t *testing.T) {
 	if err != nil {
 		t.Fatalf("Could not fetch pending transactions: %v", err)
 	}
-	nonce = pool.State().GetNonce(address)
+	nonce = pool.Nonce(address)
 	if nonce != 2 {
 		t.Fatalf("Invalid nonce, want 2, got %d", nonce)
 	}
@@ -451,7 +451,7 @@ func TestTransactionNonceRecovery(t *testing.T) {
 	// simulate some weird re-order of transactions and missing nonce(s)
 	pool.currentState.SetNonce(addr, n-1)
 	<-pool.requestReset(nil, nil)
-	if fn := pool.pendingState.GetNonce(addr); fn != n-1 {
+	if fn := pool.Nonce(addr); fn != n-1 {
 		t.Errorf("expected nonce to be %d, got %d", n-1, fn)
 	}
 }
diff --git a/eth/api_backend.go b/eth/api_backend.go
index db0e8cf410cb780af6c80b708c49d099f85ffca5..ee5b51cf5ac996abe5262890af673ef546c5b823 100644
--- a/eth/api_backend.go
+++ b/eth/api_backend.go
@@ -185,7 +185,7 @@ func (b *EthAPIBackend) GetTransaction(ctx context.Context, txHash common.Hash)
 }
 
 func (b *EthAPIBackend) GetPoolNonce(ctx context.Context, addr common.Address) (uint64, error) {
-	return b.eth.txPool.State().GetNonce(addr), nil
+	return b.eth.txPool.Nonce(addr), nil
 }
 
 func (b *EthAPIBackend) Stats() (pending int, queued int) {