diff --git a/node/src/main/kotlin/net/corda/node/services/config/NodeConfiguration.kt b/node/src/main/kotlin/net/corda/node/services/config/NodeConfiguration.kt
index 1111e9faf9..6afd7dc4a6 100644
--- a/node/src/main/kotlin/net/corda/node/services/config/NodeConfiguration.kt
+++ b/node/src/main/kotlin/net/corda/node/services/config/NodeConfiguration.kt
@@ -60,7 +60,6 @@ interface NodeConfiguration : ConfigurationWithOptionsContainer {
     val noLocalShell: Boolean get() = false
     val transactionCacheSizeBytes: Long get() = defaultTransactionCacheSize
     val attachmentContentCacheSizeBytes: Long get() = defaultAttachmentContentCacheSize
-    val attachmentCacheBound: Long get() = defaultAttachmentCacheBound
     // do not change this value without syncing it with ScheduledFlowsDrainingModeTest
     val drainingModePollPeriod: Duration get() = Duration.ofSeconds(5)
     val extraNetworkMapKeys: List<UUID>
@@ -110,7 +109,6 @@ interface NodeConfiguration : ConfigurationWithOptionsContainer {
         }
 
         internal val defaultAttachmentContentCacheSize: Long = 10.MB
-        internal const val defaultAttachmentCacheBound = 1024L
 
         const val cordappDirectoriesKey = "cordappDirectories"
 
diff --git a/node/src/main/kotlin/net/corda/node/services/config/NodeConfigurationImpl.kt b/node/src/main/kotlin/net/corda/node/services/config/NodeConfigurationImpl.kt
index 44b77a8264..49390958bf 100644
--- a/node/src/main/kotlin/net/corda/node/services/config/NodeConfigurationImpl.kt
+++ b/node/src/main/kotlin/net/corda/node/services/config/NodeConfigurationImpl.kt
@@ -65,7 +65,6 @@ data class NodeConfigurationImpl(
         override val database: DatabaseConfig = Defaults.database(devMode),
         private val transactionCacheSizeMegaBytes: Int? = Defaults.transactionCacheSizeMegaBytes,
         private val attachmentContentCacheSizeMegaBytes: Int? = Defaults.attachmentContentCacheSizeMegaBytes,
-        override val attachmentCacheBound: Long = Defaults.attachmentCacheBound,
         override val extraNetworkMapKeys: List<UUID> = Defaults.extraNetworkMapKeys,
         // do not use or remove (breaks DemoBench together with rejection of unknown configuration keys during parsing)
         private val h2port: Int? = Defaults.h2port,
@@ -112,7 +111,6 @@ data class NodeConfigurationImpl(
         const val localShellUnsafe: Boolean = false
         val transactionCacheSizeMegaBytes: Int? = null
         val attachmentContentCacheSizeMegaBytes: Int? = null
-        const val attachmentCacheBound: Long = NodeConfiguration.defaultAttachmentCacheBound
         val extraNetworkMapKeys: List<UUID> = emptyList()
         val h2port: Int? = null
         val h2Settings: NodeH2Settings? = null
diff --git a/node/src/main/kotlin/net/corda/node/services/config/schema/v1/V1NodeConfigurationSpec.kt b/node/src/main/kotlin/net/corda/node/services/config/schema/v1/V1NodeConfigurationSpec.kt
index ab1f36f417..3808597620 100644
--- a/node/src/main/kotlin/net/corda/node/services/config/schema/v1/V1NodeConfigurationSpec.kt
+++ b/node/src/main/kotlin/net/corda/node/services/config/schema/v1/V1NodeConfigurationSpec.kt
@@ -40,7 +40,6 @@ internal object V1NodeConfigurationSpec : Configuration.Specification<NodeConfig
     private val localShellUnsafe by boolean().optional().withDefaultValue(Defaults.localShellUnsafe)
     private val database by nested(DatabaseConfigSpec).optional()
     private val noLocalShell by boolean().optional().withDefaultValue(Defaults.noLocalShell)
-    private val attachmentCacheBound by long().optional().withDefaultValue(Defaults.attachmentCacheBound)
     private val extraNetworkMapKeys by string().mapValid(::toUUID).list().optional().withDefaultValue(Defaults.extraNetworkMapKeys)
     private val tlsCertCrlDistPoint by string().mapValid(::toURL).optional()
     private val tlsCertCrlIssuer by string().mapValid(::toPrincipal).optional()
@@ -118,7 +117,6 @@ internal object V1NodeConfigurationSpec : Configuration.Specification<NodeConfig
                     localShellUnsafe = config[localShellUnsafe],
                     database = database,
                     noLocalShell = config[noLocalShell],
-                    attachmentCacheBound = config[attachmentCacheBound],
                     extraNetworkMapKeys = config[extraNetworkMapKeys],
                     tlsCertCrlDistPoint = config[tlsCertCrlDistPoint],
                     tlsCertCrlIssuer = config[tlsCertCrlIssuer],
diff --git a/node/src/main/kotlin/net/corda/node/services/persistence/NodeAttachmentService.kt b/node/src/main/kotlin/net/corda/node/services/persistence/NodeAttachmentService.kt
index dbf36b9bae..9937f51a28 100644
--- a/node/src/main/kotlin/net/corda/node/services/persistence/NodeAttachmentService.kt
+++ b/node/src/main/kotlin/net/corda/node/services/persistence/NodeAttachmentService.kt
@@ -26,7 +26,6 @@ import net.corda.core.serialization.*
 import net.corda.core.utilities.contextLogger
 import net.corda.node.services.vault.HibernateAttachmentQueryCriteriaParser
 import net.corda.node.utilities.InfrequentlyMutatedCache
-import net.corda.node.utilities.NonInvalidatingCache
 import net.corda.node.utilities.NonInvalidatingWeightBasedCache
 import net.corda.nodeapi.exceptions.DuplicateAttachmentException
 import net.corda.nodeapi.internal.persistence.CordaPersistence
@@ -259,18 +258,6 @@ class NodeAttachmentService @JvmOverloads constructor(
             Token(id, checkOnLoad, uploader, signerKeys)
     }
 
-    // slightly complex 2 level approach to attachment caching:
-    // On the first level we cache attachment contents loaded from the DB by their key. This is a weight based
-    // cache (we don't want to waste too  much memory on this) and could be evicted quite aggressively. If we fail
-    // to load an attachment from the db, the loader will insert a non present optional - we invalidate this
-    // immediately as we definitely want to retry whether the attachment was just delayed.
-    // On the second level, we cache Attachment implementations that use the first cache to load their content
-    // when required. As these are fairly small, we can cache quite a lot of them, this will make checking
-    // repeatedly whether an attachment exists fairly cheap. Here as well, we evict non-existent entries immediately
-    // to force a recheck if required.
-    // If repeatedly looking for non-existing attachments becomes a performance issue, this is either indicating a
-    // a problem somewhere else or this needs to be revisited.
-
     private val attachmentContentCache = NonInvalidatingWeightBasedCache(
             cacheFactory = cacheFactory,
             name = "NodeAttachmentService_attachmentContent",
@@ -309,27 +296,13 @@ class NodeAttachmentService @JvmOverloads constructor(
         }
     }
 
-    private val attachmentCache = NonInvalidatingCache<SecureHash, Optional<Attachment>>(
-            cacheFactory = cacheFactory,
-            name = "NodeAttachmentService_attachmentPresence",
-            loadFunction = { key -> Optional.ofNullable(createAttachment(key)) })
-
-    private fun createAttachment(key: SecureHash): Attachment? {
-        val content = attachmentContentCache.get(key)!!
+    override fun openAttachment(id: SecureHash): Attachment? {
+        val content = attachmentContentCache.get(id)!!
         if (content.isPresent) {
             return content.get().first
         }
         // If no attachment has been found, we don't want to cache that - it might arrive later.
-        attachmentContentCache.invalidate(key)
-        return null
-    }
-
-    override fun openAttachment(id: SecureHash): Attachment? {
-        val attachment = attachmentCache.get(id)!!
-        if (attachment.isPresent) {
-            return attachment.get()
-        }
-        attachmentCache.invalidate(id)
+        attachmentContentCache.invalidate(id)
         return null
     }
 
@@ -426,7 +399,6 @@ class NodeAttachmentService @JvmOverloads constructor(
                         loadAttachmentContent(id)?.let { attachmentAndContent ->
                             // TODO: this is racey. ENT-2870
                             attachmentContentCache.put(id, Optional.of(attachmentAndContent))
-                            attachmentCache.put(id, Optional.of(attachmentAndContent.first))
                         }
                         return@withContractsInJar id
                     }
diff --git a/node/src/main/kotlin/net/corda/node/utilities/NodeNamedCache.kt b/node/src/main/kotlin/net/corda/node/utilities/NodeNamedCache.kt
index 3bf2bb08cf..e43b2ab7ee 100644
--- a/node/src/main/kotlin/net/corda/node/utilities/NodeNamedCache.kt
+++ b/node/src/main/kotlin/net/corda/node/utilities/NodeNamedCache.kt
@@ -43,7 +43,6 @@ open class DefaultNamedCacheFactory protected constructor(private val metricRegi
                 name == "HibernateConfiguration_sessionFactories" -> caffeine.maximumSize(database.mappedSchemaCacheSize)
                 name == "DBTransactionStorage_transactions" -> caffeine.maximumWeight(transactionCacheSizeBytes)
                 name == "NodeAttachmentService_attachmentContent" -> caffeine.maximumWeight(attachmentContentCacheSizeBytes)
-                name == "NodeAttachmentService_attachmentPresence" -> caffeine.maximumSize(attachmentCacheBound)
                 name == "NodeAttachmentService_contractAttachmentVersions" -> caffeine.maximumSize(defaultCacheSize)
                 name == "PersistentIdentityService_keyToPartyAndCert" -> caffeine.maximumSize(defaultCacheSize)
                 name == "PersistentIdentityService_nameToParty" -> caffeine.maximumSize(defaultCacheSize)