diff --git a/core/src/main/kotlin/core/node/services/IdentityService.kt b/core/src/main/kotlin/core/node/services/IdentityService.kt
index e89f3ca80b..c2006c32fd 100644
--- a/core/src/main/kotlin/core/node/services/IdentityService.kt
+++ b/core/src/main/kotlin/core/node/services/IdentityService.kt
@@ -9,6 +9,8 @@ import java.security.PublicKey
  * service would provide.
  */
 interface IdentityService {
+    fun registerIdentity(party: Party)
+    fun deregisterIdentity(party: Party)
     fun partyFromKey(key: PublicKey): Party?
     fun partyFromName(name: String): Party?
 }
diff --git a/src/main/kotlin/core/node/AbstractNode.kt b/src/main/kotlin/core/node/AbstractNode.kt
index d57d69f223..d7ff3a2dba 100644
--- a/src/main/kotlin/core/node/AbstractNode.kt
+++ b/src/main/kotlin/core/node/AbstractNode.kt
@@ -121,24 +121,14 @@ abstract class AbstractNode(val dir: Path, val configuration: NodeConfiguration,
         // know about: our own, the identity of the remote timestamper node (if any), plus whatever is in the
         // network map.
         //
-        // TODO: All this will be replaced soon enough.
-        val fixedIdentities = if (timestamperAddress != null)
-            listOf(storage.myLegalIdentity, timestamperAddress.identity)
-        else
-            listOf(storage.myLegalIdentity)
+        val service = InMemoryIdentityService()
+        if (timestamperAddress != null)
+            service.registerIdentity(timestamperAddress.identity)
+        service.registerIdentity(storage.myLegalIdentity)
 
-        return object : IdentityService {
-            private val identities: List<Party> get() = fixedIdentities + services.networkMapCache.partyNodes.map { it.identity }
-            private val keyToParties: Map<PublicKey, Party> get() = identities.associateBy { it.owningKey }
-            private val nameToParties: Map<String, Party> get() = identities.associateBy { it.name }
+        services.networkMapCache.partyNodes.forEach { service.registerIdentity(it.identity) }
 
-            override fun partyFromKey(key: PublicKey): Party? = keyToParties[key]
-            override fun partyFromName(name: String): Party? = nameToParties[name]
-
-            override fun toString(): String {
-                return identities.joinToString { it.name }
-            }
-        }
+        return service
     }
 
     open fun stop() {
diff --git a/src/main/kotlin/core/node/services/InMemoryIdentityService.kt b/src/main/kotlin/core/node/services/InMemoryIdentityService.kt
new file mode 100644
index 0000000000..2e2a1260e4
--- /dev/null
+++ b/src/main/kotlin/core/node/services/InMemoryIdentityService.kt
@@ -0,0 +1,26 @@
+package core.node.services
+
+import core.Party
+import java.security.PublicKey
+import java.util.concurrent.ConcurrentHashMap
+import javax.annotation.concurrent.ThreadSafe
+
+/**
+ * Simple identity service which caches parties and provides functionality for efficient lookup.
+ */
+@ThreadSafe
+class InMemoryIdentityService() : IdentityService {
+    private val keyToParties = ConcurrentHashMap<PublicKey, Party>()
+    private val nameToParties = ConcurrentHashMap<String, Party>()
+
+    override fun registerIdentity(party: Party) {
+        keyToParties[party.owningKey] = party
+        nameToParties[party.name] = party
+    }
+    override fun deregisterIdentity(party: Party) {
+        keyToParties.remove(party.owningKey)
+        nameToParties.remove(party.name)
+    }
+    override fun partyFromKey(key: PublicKey): Party? = keyToParties[key]
+    override fun partyFromName(name: String): Party? = nameToParties[name]
+}
\ No newline at end of file
diff --git a/src/main/kotlin/core/testing/IRSSimulation.kt b/src/main/kotlin/core/testing/IRSSimulation.kt
index e345b5ac5d..bba97c5ff7 100644
--- a/src/main/kotlin/core/testing/IRSSimulation.kt
+++ b/src/main/kotlin/core/testing/IRSSimulation.kt
@@ -7,7 +7,7 @@ import com.google.common.util.concurrent.SettableFuture
 import contracts.InterestRateSwap
 import core.*
 import core.crypto.SecureHash
-import core.node.services.FixedIdentityService
+import core.testing.MockIdentityService
 import core.node.services.linearHeadsOfType
 import core.utilities.JsonSupport
 import protocols.TwoPartyDealProtocol
@@ -19,7 +19,7 @@ import java.util.*
  * A simulation in which banks execute interest rate swaps with each other, including the fixing events.
  */
 class IRSSimulation(runAsync: Boolean, latencyInjector: InMemoryMessagingNetwork.LatencyCalculator?) : Simulation(runAsync, latencyInjector) {
-    val om = JsonSupport.createDefaultMapper(FixedIdentityService(network.identities))
+    val om = JsonSupport.createDefaultMapper(MockIdentityService(network.identities))
 
     init {
         currentDay = LocalDate.of(2016, 3, 10)   // Should be 12th but the actual first fixing date gets rolled backwards.
diff --git a/src/main/kotlin/core/node/services/FixedIdentityService.kt b/src/main/kotlin/core/testing/MockIdentityService.kt
similarity index 73%
rename from src/main/kotlin/core/node/services/FixedIdentityService.kt
rename to src/main/kotlin/core/testing/MockIdentityService.kt
index 970d49459b..7772238ae4 100644
--- a/src/main/kotlin/core/node/services/FixedIdentityService.kt
+++ b/src/main/kotlin/core/testing/MockIdentityService.kt
@@ -1,6 +1,7 @@
-package core.node.services
+package core.testing
 
 import core.Party
+import core.node.services.IdentityService
 import java.security.PublicKey
 import javax.annotation.concurrent.ThreadSafe
 
@@ -11,12 +12,14 @@ import javax.annotation.concurrent.ThreadSafe
  * MockNetwork code.
  */
 @ThreadSafe
-class FixedIdentityService(val identities: List<Party>) : IdentityService {
+class MockIdentityService(val identities: List<Party>) : IdentityService {
     private val keyToParties: Map<PublicKey, Party>
         get() = synchronized(identities) { identities.associateBy { it.owningKey } }
     private val nameToParties: Map<String, Party>
         get() = synchronized(identities) { identities.associateBy { it.name } }
 
+    override fun registerIdentity(party: Party) { throw UnsupportedOperationException() }
+    override fun deregisterIdentity(party: Party) { throw UnsupportedOperationException() }
     override fun partyFromKey(key: PublicKey): Party? = keyToParties[key]
     override fun partyFromName(name: String): Party? = nameToParties[name]
 }
\ No newline at end of file
diff --git a/src/main/kotlin/core/testing/MockNode.kt b/src/main/kotlin/core/testing/MockNode.kt
index cb80723923..548d0410fb 100644
--- a/src/main/kotlin/core/testing/MockNode.kt
+++ b/src/main/kotlin/core/testing/MockNode.kt
@@ -9,7 +9,7 @@ import core.node.AbstractNode
 import core.node.NodeConfiguration
 import core.node.NodeInfo
 import core.node.PhysicalLocation
-import core.node.services.FixedIdentityService
+import core.testing.MockIdentityService
 import core.node.services.ServiceType
 import core.node.services.TimestamperService
 import core.utilities.loggerFor
@@ -75,7 +75,7 @@ class MockNetwork(private val threadPerNode: Boolean = false,
             return mockNet.messagingNetwork.createNodeWithID(!mockNet.threadPerNode, id).start().get()
         }
 
-        override fun makeIdentityService() = FixedIdentityService(mockNet.identities)
+        override fun makeIdentityService() = MockIdentityService(mockNet.identities)
 
         // There is no need to slow down the unit tests by initialising CityDatabase
         override fun findMyLocation(): PhysicalLocation? = null
diff --git a/src/main/kotlin/demos/IRSDemo.kt b/src/main/kotlin/demos/IRSDemo.kt
index d4d235fb67..1ff7339bbe 100644
--- a/src/main/kotlin/demos/IRSDemo.kt
+++ b/src/main/kotlin/demos/IRSDemo.kt
@@ -108,6 +108,7 @@ fun main(args: Array<String>) {
         try {
             val peerId = nodeInfo(hostAndPortString, identityFile)
             (node.services.networkMapCache as MockNetworkMapCache).partyNodes.add(peerId)
+            node.services.identityService.registerIdentity(peerId.identity)
         } catch (e: Exception) {
         }
     }
diff --git a/src/test/kotlin/core/testutils/TestUtils.kt b/src/test/kotlin/core/testutils/TestUtils.kt
index 2ec2e02af7..6d71d0e2af 100644
--- a/src/test/kotlin/core/testutils/TestUtils.kt
+++ b/src/test/kotlin/core/testutils/TestUtils.kt
@@ -7,7 +7,7 @@ import contracts.*
 import core.*
 import core.crypto.*
 import core.node.services.DummyTimestampingAuthority
-import core.node.services.FixedIdentityService
+import core.testing.MockIdentityService
 import core.serialization.serialize
 import core.visualiser.GraphVisualiser
 import java.security.KeyPair
@@ -60,7 +60,7 @@ val MINI_CORP = Party("MiniCorp", MINI_CORP_PUBKEY)
 
 val ALL_TEST_KEYS = listOf(MEGA_CORP_KEY, MINI_CORP_KEY, ALICE_KEY, BOB_KEY, DummyTimestampingAuthority.key)
 
-val MockIdentityService = FixedIdentityService(listOf(MEGA_CORP, MINI_CORP, DUMMY_TIMESTAMPER.identity))
+val MockIdentityService = MockIdentityService(listOf(MEGA_CORP, MINI_CORP, DUMMY_TIMESTAMPER.identity))
 
 // In a real system this would be a persistent map of hash to bytecode and we'd instantiate the object as needed inside
 // a sandbox. For unit tests we just have a hard-coded list.