diff --git a/Corona-Warn-App/src/deviceForTesters/java/de/rki/coronawarnapp/test/api/ui/TestForAPIFragment.kt b/Corona-Warn-App/src/deviceForTesters/java/de/rki/coronawarnapp/test/api/ui/TestForAPIFragment.kt
index 15968158f9b4d89f681d127bba1cdfc97559bd9e..03594794e6724dd7f620ab2281dae3b4f7762fe9 100644
--- a/Corona-Warn-App/src/deviceForTesters/java/de/rki/coronawarnapp/test/api/ui/TestForAPIFragment.kt
+++ b/Corona-Warn-App/src/deviceForTesters/java/de/rki/coronawarnapp/test/api/ui/TestForAPIFragment.kt
@@ -26,6 +26,7 @@ import com.google.zxing.integration.android.IntentIntegrator
 import com.google.zxing.integration.android.IntentResult
 import com.google.zxing.qrcode.QRCodeWriter
 import de.rki.coronawarnapp.R
+import de.rki.coronawarnapp.appconfig.AppConfigProvider
 import de.rki.coronawarnapp.databinding.FragmentTestForAPIBinding
 import de.rki.coronawarnapp.exception.ExceptionCategory
 import de.rki.coronawarnapp.exception.ExceptionCategory.INTERNAL
@@ -65,6 +66,9 @@ class TestForAPIFragment : Fragment(R.layout.fragment_test_for_a_p_i),
 
     @Inject lateinit var viewModelFactory: CWAViewModelFactoryProvider.Factory
     @Inject lateinit var enfClient: ENFClient
+
+    // TODO: This is ugly, remove when refactoring the fragment
+    @Inject lateinit var appConfigProvider: AppConfigProvider
     @Inject lateinit var riskLevelStorage: RiskLevelStorage
     private val vm: TestForApiFragmentViewModel by cwaViewModels { viewModelFactory }
 
@@ -291,7 +295,8 @@ class TestForAPIFragment : Fragment(R.layout.fragment_test_for_a_p_i),
                 try {
                     // only testing implementation: this is used to wait for the broadcastreceiver of the OS / EN API
                     enfClient.provideDiagnosisKeys(
-                        googleFileList
+                        googleFileList,
+                        appConfigProvider.getAppConfig().diagnosisKeysDataMapping
                     )
                     showToast("Provided ${appleKeyList.size} keys to Google API")
                 } catch (e: Exception) {
diff --git a/Corona-Warn-App/src/main/assets/default_app_config_android.bin b/Corona-Warn-App/src/main/assets/default_app_config_android.bin
index 72e76a3f1f0b4b5fe7275c9d0052477df4b0a129..e1e0e0b2b339e4b247d14d3017298353efef2f1e 100644
Binary files a/Corona-Warn-App/src/main/assets/default_app_config_android.bin and b/Corona-Warn-App/src/main/assets/default_app_config_android.bin differ
diff --git a/Corona-Warn-App/src/main/assets/default_app_config_android.sha256 b/Corona-Warn-App/src/main/assets/default_app_config_android.sha256
index ce41e9e2b98f97be0e8e4fb9b2ccd4d7cce1bf6b..ce2ef522ef7e6c73a130ab5a84a47089c9e299e7 100644
--- a/Corona-Warn-App/src/main/assets/default_app_config_android.sha256
+++ b/Corona-Warn-App/src/main/assets/default_app_config_android.sha256
@@ -1 +1 @@
-3713298c705ee867f0b12cd2a05bc6209442baa156d8e38e19856a3a6b91a48e
\ No newline at end of file
+665e82fa8d333eea36c5bda14f22f4519dc7d1a9dc890872ce8bc07880030bf1
\ No newline at end of file
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/appconfig/ExposureWindowRiskCalculationConfig.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/appconfig/ExposureWindowRiskCalculationConfig.kt
index 80eadd589d6bf68fc19648513195ab5e36841036..cf72d970a6f1ea04e86bf7530fe85b156f976322 100644
--- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/appconfig/ExposureWindowRiskCalculationConfig.kt
+++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/appconfig/ExposureWindowRiskCalculationConfig.kt
@@ -1,5 +1,6 @@
 package de.rki.coronawarnapp.appconfig
 
+import com.google.android.gms.nearby.exposurenotification.DiagnosisKeysDataMapping
 import de.rki.coronawarnapp.server.protocols.internal.v2.AppConfigAndroid
 import de.rki.coronawarnapp.server.protocols.internal.v2.RiskCalculationParametersOuterClass
 
@@ -13,6 +14,7 @@ interface ExposureWindowRiskCalculationConfig {
         List<RiskCalculationParametersOuterClass.NormalizedTimeToRiskLevelMapping>
     val normalizedTimePerDayToRiskLevelMappingList:
         List<RiskCalculationParametersOuterClass.NormalizedTimeToRiskLevelMapping>
+    val diagnosisKeysDataMapping: DiagnosisKeysDataMapping
 
     interface Mapper {
         fun map(rawConfig: AppConfigAndroid.ApplicationConfigurationAndroid): ExposureWindowRiskCalculationConfig
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/appconfig/mapping/ExposureWindowRiskCalculationConfigMapper.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/appconfig/mapping/ExposureWindowRiskCalculationConfigMapper.kt
index ab55b97ee827ef27a091e1575c0eae048e50ee7a..607c0d8d0ed2019165a2705693411f70c4ef9d7f 100644
--- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/appconfig/mapping/ExposureWindowRiskCalculationConfigMapper.kt
+++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/appconfig/mapping/ExposureWindowRiskCalculationConfigMapper.kt
@@ -1,5 +1,6 @@
 package de.rki.coronawarnapp.appconfig.mapping
 
+import com.google.android.gms.nearby.exposurenotification.DiagnosisKeysDataMapping
 import dagger.Reusable
 import de.rki.coronawarnapp.appconfig.ExposureWindowRiskCalculationConfig
 import de.rki.coronawarnapp.appconfig.internal.ApplicationConfigurationInvalidException
@@ -18,6 +19,12 @@ class ExposureWindowRiskCalculationConfigMapper @Inject constructor() :
             )
         }
 
+        if (!rawConfig.hasDiagnosisKeysDataMapping()) {
+            throw ApplicationConfigurationInvalidException(
+                message = "Diagnosis Keys Data Mapping is missing"
+            )
+        }
+
         val riskCalculationParameters = rawConfig.riskCalculationParameters
 
         return ExposureWindowRiskCalculationContainer(
@@ -34,10 +41,24 @@ class ExposureWindowRiskCalculationConfigMapper @Inject constructor() :
             normalizedTimePerExposureWindowToRiskLevelMapping = riskCalculationParameters
                 .normalizedTimePerEWToRiskLevelMappingList,
             normalizedTimePerDayToRiskLevelMappingList = riskCalculationParameters
-                .normalizedTimePerDayToRiskLevelMappingList
+                .normalizedTimePerDayToRiskLevelMappingList,
+            diagnosisKeysDataMapping = rawConfig.diagnosisKeysDataMapping()
         )
     }
 
+    private fun AppConfigAndroid.ApplicationConfigurationAndroid.diagnosisKeysDataMapping():
+        DiagnosisKeysDataMapping {
+        val diagnosisKeyDataMapping = this.diagnosisKeysDataMapping
+        return DiagnosisKeysDataMapping.DiagnosisKeysDataMappingBuilder()
+            .apply {
+                setDaysSinceOnsetToInfectiousness(diagnosisKeyDataMapping.daysSinceOnsetToInfectiousnessMap)
+                setInfectiousnessWhenDaysSinceOnsetMissing(
+                    diagnosisKeysDataMapping.infectiousnessWhenDaysSinceOnsetMissing
+                )
+                setReportTypeWhenMissing(diagnosisKeysDataMapping.reportTypeWhenMissing)
+            }.build()
+    }
+
     data class ExposureWindowRiskCalculationContainer(
         override val minutesAtAttenuationFilters: List<RiskCalculationParametersOuterClass.MinutesAtAttenuationFilter>,
         override val minutesAtAttenuationWeights: List<RiskCalculationParametersOuterClass.MinutesAtAttenuationWeight>,
@@ -47,6 +68,7 @@ class ExposureWindowRiskCalculationConfigMapper @Inject constructor() :
         override val normalizedTimePerExposureWindowToRiskLevelMapping:
         List<RiskCalculationParametersOuterClass.NormalizedTimeToRiskLevelMapping>,
         override val normalizedTimePerDayToRiskLevelMappingList:
-        List<RiskCalculationParametersOuterClass.NormalizedTimeToRiskLevelMapping>
+        List<RiskCalculationParametersOuterClass.NormalizedTimeToRiskLevelMapping>,
+        override val diagnosisKeysDataMapping: DiagnosisKeysDataMapping
     ) : ExposureWindowRiskCalculationConfig
 }
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/diagnosiskeys/download/DownloadDiagnosisKeysTask.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/diagnosiskeys/download/DownloadDiagnosisKeysTask.kt
index d04dc5137d1dc33c3eb31577ef33fade451f4594..8f34bcc8ced3d56d3c19ba2269e5a02e4be119b4 100644
--- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/diagnosiskeys/download/DownloadDiagnosisKeysTask.kt
+++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/diagnosiskeys/download/DownloadDiagnosisKeysTask.kt
@@ -1,6 +1,7 @@
 package de.rki.coronawarnapp.diagnosiskeys.download
 
 import de.rki.coronawarnapp.appconfig.AppConfigProvider
+import de.rki.coronawarnapp.appconfig.ConfigData
 import de.rki.coronawarnapp.appconfig.ExposureDetectionConfig
 import de.rki.coronawarnapp.diagnosiskeys.server.LocationCode
 import de.rki.coronawarnapp.environment.EnvironmentSetup
@@ -63,7 +64,7 @@ class DownloadDiagnosisKeysTask @Inject constructor(
             throwIfCancelled()
 
             // RETRIEVE RISK SCORE PARAMETERS
-            val exposureConfig: ExposureDetectionConfig = appConfigProvider.getAppConfig()
+            val exposureConfig: ConfigData = appConfigProvider.getAppConfig()
 
             internalProgress.send(Progress.ApiSubmissionStarted)
             internalProgress.send(Progress.KeyFilesDownloadStarted)
@@ -102,7 +103,10 @@ class DownloadDiagnosisKeysTask @Inject constructor(
             )
 
             Timber.tag(TAG).d("Attempting submission to ENF")
-            val isSubmissionSuccessful = enfClient.provideDiagnosisKeys(availableKeyFiles)
+            val isSubmissionSuccessful = enfClient.provideDiagnosisKeys(
+                availableKeyFiles,
+                exposureConfig.diagnosisKeysDataMapping
+            )
             Timber.tag(TAG).d("Diagnosis Keys provided (success=%s)", isSubmissionSuccessful)
 
             // EXPOSUREAPP-3878 write timestamp immediately after submission,
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/nearby/ENFClient.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/nearby/ENFClient.kt
index 587603da757c029bf13e0a553538130c9737fa96..4838e9ceeac1340f3a7bd07671e84e8b6dd712bc 100644
--- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/nearby/ENFClient.kt
+++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/nearby/ENFClient.kt
@@ -2,6 +2,7 @@
 
 package de.rki.coronawarnapp.nearby
 
+import com.google.android.gms.nearby.exposurenotification.DiagnosisKeysDataMapping
 import com.google.android.gms.nearby.exposurenotification.ExposureNotificationClient
 import com.google.android.gms.nearby.exposurenotification.ExposureWindow
 import de.rki.coronawarnapp.nearby.modules.detectiontracker.ExposureDetectionTracker
@@ -36,7 +37,10 @@ class ENFClient @Inject constructor(
     internal val internalClient: ExposureNotificationClient
         get() = googleENFClient
 
-    override suspend fun provideDiagnosisKeys(keyFiles: Collection<File>): Boolean {
+    override suspend fun provideDiagnosisKeys(
+        keyFiles: Collection<File>,
+        newDiagnosisKeysDataMapping: DiagnosisKeysDataMapping
+    ): Boolean {
         Timber.d("asyncProvideDiagnosisKeys(keyFiles=$keyFiles)")
 
         return if (keyFiles.isEmpty()) {
@@ -45,7 +49,7 @@ class ENFClient @Inject constructor(
         } else {
             Timber.d("Forwarding %d key files to our DiagnosisKeyProvider.", keyFiles.size)
             exposureDetectionTracker.trackNewExposureDetection(UUID.randomUUID().toString())
-            diagnosisKeyProvider.provideDiagnosisKeys(keyFiles)
+            diagnosisKeyProvider.provideDiagnosisKeys(keyFiles, newDiagnosisKeysDataMapping)
         }
     }
 
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/nearby/ENFModule.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/nearby/ENFModule.kt
index 1d4220ee0df1f0640c4d5587ddd56bfdbd669e77..cbf0c96de676d53d0f59d28aad11c4ea4ee121e5 100644
--- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/nearby/ENFModule.kt
+++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/nearby/ENFModule.kt
@@ -9,6 +9,8 @@ import de.rki.coronawarnapp.nearby.modules.detectiontracker.DefaultExposureDetec
 import de.rki.coronawarnapp.nearby.modules.detectiontracker.ExposureDetectionTracker
 import de.rki.coronawarnapp.nearby.modules.diagnosiskeyprovider.DefaultDiagnosisKeyProvider
 import de.rki.coronawarnapp.nearby.modules.diagnosiskeyprovider.DiagnosisKeyProvider
+import de.rki.coronawarnapp.nearby.modules.diagnosiskeysdatamapper.DefaultDiagnosisKeysDataMapper
+import de.rki.coronawarnapp.nearby.modules.diagnosiskeysdatamapper.DiagnosisKeysDataMapper
 import de.rki.coronawarnapp.nearby.modules.exposurewindow.DefaultExposureWindowProvider
 import de.rki.coronawarnapp.nearby.modules.exposurewindow.ExposureWindowProvider
 import de.rki.coronawarnapp.nearby.modules.locationless.DefaultScanningSupport
@@ -48,6 +50,11 @@ class ENFModule {
     fun exposureWindowProvider(exposureWindowProvider: DefaultExposureWindowProvider): ExposureWindowProvider =
         exposureWindowProvider
 
+    @Singleton
+    @Provides
+    fun diagnosisKeysDataMapper(diagnosisKeysDataMapper: DefaultDiagnosisKeysDataMapper):
+        DiagnosisKeysDataMapper = diagnosisKeysDataMapper
+
     @Singleton
     @Provides
     fun calculationTracker(exposureDetectionTracker: DefaultExposureDetectionTracker): ExposureDetectionTracker =
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/nearby/modules/diagnosiskeyprovider/DefaultDiagnosisKeyProvider.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/nearby/modules/diagnosiskeyprovider/DefaultDiagnosisKeyProvider.kt
index 2c5924ec9f54992538ea1c132b41c43fe5aece47..3f22ca8519ee4791d8639b77d794ed21ec81ab1c 100644
--- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/nearby/modules/diagnosiskeyprovider/DefaultDiagnosisKeyProvider.kt
+++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/nearby/modules/diagnosiskeyprovider/DefaultDiagnosisKeyProvider.kt
@@ -1,9 +1,11 @@
 package de.rki.coronawarnapp.nearby.modules.diagnosiskeyprovider
 
 import com.google.android.gms.common.api.ApiException
+import com.google.android.gms.nearby.exposurenotification.DiagnosisKeysDataMapping
 import com.google.android.gms.nearby.exposurenotification.DiagnosisKeyFileProvider
 import com.google.android.gms.nearby.exposurenotification.ExposureNotificationClient
 import de.rki.coronawarnapp.exception.reporting.ReportingConstants
+import de.rki.coronawarnapp.nearby.modules.diagnosiskeysdatamapper.DiagnosisKeysDataMapper
 import de.rki.coronawarnapp.nearby.modules.version.ENFVersion
 import timber.log.Timber
 import java.io.File
@@ -17,10 +19,16 @@ import kotlin.coroutines.suspendCoroutine
 class DefaultDiagnosisKeyProvider @Inject constructor(
     private val enfVersion: ENFVersion,
     private val submissionQuota: SubmissionQuota,
-    private val enfClient: ExposureNotificationClient
+    private val enfClient: ExposureNotificationClient,
+    private val diagnosisKeysDataMapper: DiagnosisKeysDataMapper
 ) : DiagnosisKeyProvider {
 
-    override suspend fun provideDiagnosisKeys(keyFiles: Collection<File>): Boolean {
+    override suspend fun provideDiagnosisKeys(
+        keyFiles: Collection<File>,
+        newDiagnosisKeysDataMapping: DiagnosisKeysDataMapping
+    ): Boolean {
+        diagnosisKeysDataMapper.updateDiagnosisKeysDataMapping(newDiagnosisKeysDataMapping)
+
         if (keyFiles.isEmpty()) {
             Timber.d("No key files submitted, returning early.")
             return true
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/nearby/modules/diagnosiskeyprovider/DiagnosisKeyProvider.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/nearby/modules/diagnosiskeyprovider/DiagnosisKeyProvider.kt
index b3339619f5b4e96635d1326a43cfb8d1cc09951e..14e67c266290a30290e3bab27b0a8c413c8fc4e7 100644
--- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/nearby/modules/diagnosiskeyprovider/DiagnosisKeyProvider.kt
+++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/nearby/modules/diagnosiskeyprovider/DiagnosisKeyProvider.kt
@@ -1,5 +1,6 @@
 package de.rki.coronawarnapp.nearby.modules.diagnosiskeyprovider
 
+import com.google.android.gms.nearby.exposurenotification.DiagnosisKeysDataMapping
 import java.io.File
 
 interface DiagnosisKeyProvider {
@@ -15,5 +16,8 @@ interface DiagnosisKeyProvider {
      * @return
      */
 
-    suspend fun provideDiagnosisKeys(keyFiles: Collection<File>): Boolean
+    suspend fun provideDiagnosisKeys(
+        keyFiles: Collection<File>,
+        newDiagnosisKeysDataMapping: DiagnosisKeysDataMapping
+    ): Boolean
 }
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/nearby/modules/diagnosiskeysdatamapper/DefaultDiagnosisKeysDataMapper.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/nearby/modules/diagnosiskeysdatamapper/DefaultDiagnosisKeysDataMapper.kt
new file mode 100644
index 0000000000000000000000000000000000000000..7f018e89cac0b2f5ecf64a4faacfe2779547fbfe
--- /dev/null
+++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/nearby/modules/diagnosiskeysdatamapper/DefaultDiagnosisKeysDataMapper.kt
@@ -0,0 +1,64 @@
+package de.rki.coronawarnapp.nearby.modules.diagnosiskeysdatamapper
+
+import com.google.android.gms.common.api.ApiException
+import com.google.android.gms.nearby.exposurenotification.DiagnosisKeysDataMapping
+import com.google.android.gms.nearby.exposurenotification.ExposureNotificationClient
+import com.google.android.gms.nearby.exposurenotification.ExposureNotificationStatusCodes.FAILED_RATE_LIMITED
+import timber.log.Timber
+import javax.inject.Inject
+import javax.inject.Singleton
+import kotlin.coroutines.resume
+import kotlin.coroutines.resumeWithException
+import kotlin.coroutines.suspendCoroutine
+
+@Singleton
+class DefaultDiagnosisKeysDataMapper @Inject constructor(
+    private val client: ExposureNotificationClient
+) : DiagnosisKeysDataMapper {
+    private suspend fun getDiagnosisKeysDataMapping(): DiagnosisKeysDataMapping? =
+        suspendCoroutine { cont ->
+            client.diagnosisKeysDataMapping
+                .addOnSuccessListener { cont.resume(it) }
+                .addOnFailureListener { cont.resumeWithException(it) }
+        }
+
+    private suspend fun setDiagnosisKeysDataMapping(diagnosisKeysDataMapping: DiagnosisKeysDataMapping) =
+        suspendCoroutine<Unit> { cont ->
+            client.setDiagnosisKeysDataMapping(diagnosisKeysDataMapping)
+                .addOnSuccessListener { cont.resume(Unit) }
+                .addOnFailureListener { cont.resumeWithException(it) }
+        }
+
+    override suspend fun updateDiagnosisKeysDataMapping(newDiagnosisKeysDataMapping: DiagnosisKeysDataMapping) {
+        val currentDiagnosisKeysDataMapping =
+            try {
+                getDiagnosisKeysDataMapping()
+            } catch (e: Exception) {
+                Timber.e("Failed to get the current DiagnosisKeysDataMapping assuming none present")
+                null
+            }
+
+        if (newDiagnosisKeysDataMapping.hasChanged(currentDiagnosisKeysDataMapping)) {
+            try {
+                Timber.i(
+                    "Current DiagnosisKeysDataMapping: %s vs new: %s, applying new version.",
+                    currentDiagnosisKeysDataMapping,
+                    newDiagnosisKeysDataMapping
+                )
+                setDiagnosisKeysDataMapping(newDiagnosisKeysDataMapping)
+            } catch (e: ApiException) {
+                if (e.statusCode == FAILED_RATE_LIMITED) {
+                    Timber.e(e, "Failed to setDiagnosisKeysDataMapping due to rate limit ")
+                } else {
+                    throw e
+                }
+            }
+        }
+    }
+
+    companion object {
+        fun DiagnosisKeysDataMapping?.hasChanged(old: DiagnosisKeysDataMapping?): Boolean {
+            return old == null || old.hashCode() != hashCode()
+        }
+    }
+}
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/nearby/modules/diagnosiskeysdatamapper/DiagnosisKeysDataMapper.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/nearby/modules/diagnosiskeysdatamapper/DiagnosisKeysDataMapper.kt
new file mode 100644
index 0000000000000000000000000000000000000000..99cdec102fa88402e49c66f18e62e9553d30858b
--- /dev/null
+++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/nearby/modules/diagnosiskeysdatamapper/DiagnosisKeysDataMapper.kt
@@ -0,0 +1,7 @@
+package de.rki.coronawarnapp.nearby.modules.diagnosiskeysdatamapper
+
+import com.google.android.gms.nearby.exposurenotification.DiagnosisKeysDataMapping
+
+interface DiagnosisKeysDataMapper {
+    suspend fun updateDiagnosisKeysDataMapping(newDiagnosisKeysDataMapping: DiagnosisKeysDataMapping)
+}
diff --git a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/appconfig/sources/fallback/DefaultAppConfigSanityCheck.kt b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/appconfig/sources/fallback/DefaultAppConfigSanityCheck.kt
index c9459763b063371cb4d0630ac7b7ff0b483dd090..fa6cb5ee2c3502fbea1657096b9e12316febbd1e 100644
--- a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/appconfig/sources/fallback/DefaultAppConfigSanityCheck.kt
+++ b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/appconfig/sources/fallback/DefaultAppConfigSanityCheck.kt
@@ -47,7 +47,7 @@ class DefaultAppConfigSanityCheck : BaseTest() {
     fun `current default matches checksum`() {
         val config = context.assets.open(configName).readBytes()
         val sha256 = context.assets.open(checkSumName).readBytes().toString(Charsets.UTF_8)
-        sha256 shouldBe "3713298c705ee867f0b12cd2a05bc6209442baa156d8e38e19856a3a6b91a48e"
+        sha256 shouldBe "665e82fa8d333eea36c5bda14f22f4519dc7d1a9dc890872ce8bc07880030bf1"
         config.toSHA256() shouldBe sha256
     }
 
diff --git a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/nearby/ENFClientTest.kt b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/nearby/ENFClientTest.kt
index b24f8fc8964adf921e00389250ed379eb54ea4d1..39e4639e53407bb9b4e1066c2a203045f8f5c364 100644
--- a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/nearby/ENFClientTest.kt
+++ b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/nearby/ENFClientTest.kt
@@ -19,6 +19,7 @@ import io.mockk.coVerifySequence
 import io.mockk.every
 import io.mockk.impl.annotations.MockK
 import io.mockk.just
+import io.mockk.mockk
 import io.mockk.verifySequence
 import kotlinx.coroutines.flow.first
 import kotlinx.coroutines.flow.flowOf
@@ -45,7 +46,7 @@ class ENFClientTest : BaseTest() {
     @BeforeEach
     fun setup() {
         MockKAnnotations.init(this)
-        coEvery { diagnosisKeyProvider.provideDiagnosisKeys(any()) } returns true
+        coEvery { diagnosisKeyProvider.provideDiagnosisKeys(any(), any()) } returns true
         every { exposureDetectionTracker.trackNewExposureDetection(any()) } just Runs
     }
 
@@ -75,19 +76,20 @@ class ENFClientTest : BaseTest() {
         val client = createClient()
         val keyFiles = listOf(File("test"))
 
-        coEvery { diagnosisKeyProvider.provideDiagnosisKeys(any()) } returns true
+        coEvery { diagnosisKeyProvider.provideDiagnosisKeys(any(), any()) } returns true
         runBlocking {
-            client.provideDiagnosisKeys(keyFiles) shouldBe true
+            client.provideDiagnosisKeys(keyFiles, mockk()) shouldBe true
         }
 
-        coEvery { diagnosisKeyProvider.provideDiagnosisKeys(any()) } returns false
+        coEvery { diagnosisKeyProvider.provideDiagnosisKeys(any(), any()) } returns false
         runBlocking {
-            client.provideDiagnosisKeys(keyFiles) shouldBe false
+            client.provideDiagnosisKeys(keyFiles, mockk()) shouldBe false
         }
 
         coVerify(exactly = 2) {
             diagnosisKeyProvider.provideDiagnosisKeys(
-                keyFiles
+                keyFiles,
+                any()
             )
         }
     }
@@ -97,13 +99,13 @@ class ENFClientTest : BaseTest() {
         val client = createClient()
         val keyFiles = emptyList<File>()
 
-        coEvery { diagnosisKeyProvider.provideDiagnosisKeys(any()) } returns true
+        coEvery { diagnosisKeyProvider.provideDiagnosisKeys(any(), any()) } returns true
         runBlocking {
-            client.provideDiagnosisKeys(keyFiles) shouldBe true
+            client.provideDiagnosisKeys(keyFiles, mockk()) shouldBe true
         }
 
         coVerify(exactly = 0) {
-            diagnosisKeyProvider.provideDiagnosisKeys(any())
+            diagnosisKeyProvider.provideDiagnosisKeys(any(), any())
         }
     }
 
diff --git a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/nearby/modules/diagnosiskeyprovider/DefaultDiagnosisKeyProviderTest.kt b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/nearby/modules/diagnosiskeyprovider/DefaultDiagnosisKeyProviderTest.kt
index 3092fb5d3457283c591e17720f3efba28f1f880e..034c9d9e36c38cd3c0de667fcc78aa61fc4335c1 100644
--- a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/nearby/modules/diagnosiskeyprovider/DefaultDiagnosisKeyProviderTest.kt
+++ b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/nearby/modules/diagnosiskeyprovider/DefaultDiagnosisKeyProviderTest.kt
@@ -2,16 +2,20 @@ package de.rki.coronawarnapp.nearby.modules.diagnosiskeyprovider
 
 import com.google.android.gms.nearby.exposurenotification.DiagnosisKeyFileProvider
 import com.google.android.gms.nearby.exposurenotification.ExposureNotificationClient
+import de.rki.coronawarnapp.nearby.modules.diagnosiskeysdatamapper.DiagnosisKeysDataMapper
 import de.rki.coronawarnapp.nearby.modules.version.ENFVersion
 import de.rki.coronawarnapp.nearby.modules.version.OutdatedENFVersionException
 import io.kotest.matchers.shouldBe
 import io.mockk.Called
 import io.mockk.MockKAnnotations
+import io.mockk.Runs
 import io.mockk.clearAllMocks
 import io.mockk.coEvery
 import io.mockk.coVerify
 import io.mockk.coVerifySequence
 import io.mockk.impl.annotations.MockK
+import io.mockk.just
+import io.mockk.mockk
 import kotlinx.coroutines.runBlocking
 import kotlinx.coroutines.test.runBlockingTest
 import org.junit.jupiter.api.AfterEach
@@ -26,6 +30,7 @@ class DefaultDiagnosisKeyProviderTest : BaseTest() {
     @MockK lateinit var googleENFClient: ExposureNotificationClient
     @MockK lateinit var enfVersion: ENFVersion
     @MockK lateinit var submissionQuota: SubmissionQuota
+    @MockK lateinit var diagnosisKeysDataMapper: DiagnosisKeysDataMapper
 
     private val exampleKeyFiles = listOf(File("file1"), File("file2"))
 
@@ -33,6 +38,8 @@ class DefaultDiagnosisKeyProviderTest : BaseTest() {
     fun setup() {
         MockKAnnotations.init(this)
 
+        coEvery { diagnosisKeysDataMapper.updateDiagnosisKeysDataMapping(any()) } just Runs
+
         coEvery { submissionQuota.consumeQuota(any()) } returns true
 
         coEvery { googleENFClient.provideDiagnosisKeys(any<List<File>>()) } returns MockGMSTask.forValue(null)
@@ -50,7 +57,8 @@ class DefaultDiagnosisKeyProviderTest : BaseTest() {
     private fun createProvider() = DefaultDiagnosisKeyProvider(
         enfVersion = enfVersion,
         submissionQuota = submissionQuota,
-        enfClient = googleENFClient
+        enfClient = googleENFClient,
+        diagnosisKeysDataMapper = diagnosisKeysDataMapper
     )
 
     @Test
@@ -63,7 +71,7 @@ class DefaultDiagnosisKeyProviderTest : BaseTest() {
         val provider = createProvider()
 
         assertThrows<OutdatedENFVersionException> {
-            runBlockingTest { provider.provideDiagnosisKeys(exampleKeyFiles) } shouldBe false
+            runBlockingTest { provider.provideDiagnosisKeys(exampleKeyFiles, mockk()) } shouldBe false
         }
 
         coVerify {
@@ -78,7 +86,7 @@ class DefaultDiagnosisKeyProviderTest : BaseTest() {
 
         val provider = createProvider()
 
-        runBlocking { provider.provideDiagnosisKeys(exampleKeyFiles) } shouldBe true
+        runBlocking { provider.provideDiagnosisKeys(exampleKeyFiles, mockk()) } shouldBe true
 
         coVerifySequence {
             submissionQuota.consumeQuota(1)
@@ -92,7 +100,7 @@ class DefaultDiagnosisKeyProviderTest : BaseTest() {
 
         val provider = createProvider()
 
-        runBlocking { provider.provideDiagnosisKeys(exampleKeyFiles) } shouldBe true
+        runBlocking { provider.provideDiagnosisKeys(exampleKeyFiles, mockk()) } shouldBe true
 
         coVerifySequence {
             submissionQuota.consumeQuota(1)
@@ -107,7 +115,7 @@ class DefaultDiagnosisKeyProviderTest : BaseTest() {
 
         val provider = createProvider()
 
-        runBlocking { provider.provideDiagnosisKeys(exampleKeyFiles) } shouldBe true
+        runBlocking { provider.provideDiagnosisKeys(exampleKeyFiles, mockk()) } shouldBe true
 
         coVerifySequence {
             submissionQuota.consumeQuota(1)
@@ -119,7 +127,7 @@ class DefaultDiagnosisKeyProviderTest : BaseTest() {
     fun `provide empty key list`() {
         val provider = createProvider()
 
-        runBlocking { provider.provideDiagnosisKeys(emptyList()) } shouldBe true
+        runBlocking { provider.provideDiagnosisKeys(emptyList(), mockk()) } shouldBe true
 
         coVerify {
             googleENFClient wasNot Called
diff --git a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/nearby/modules/diagnosiskeysdatamapper/DefaultDiagnosisKeysDataMapperTest.kt b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/nearby/modules/diagnosiskeysdatamapper/DefaultDiagnosisKeysDataMapperTest.kt
new file mode 100644
index 0000000000000000000000000000000000000000..188056cc3e4bc6e74515a34cc305ee1b268e1907
--- /dev/null
+++ b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/nearby/modules/diagnosiskeysdatamapper/DefaultDiagnosisKeysDataMapperTest.kt
@@ -0,0 +1,138 @@
+package de.rki.coronawarnapp.nearby.modules.diagnosiskeysdatamapper
+
+import com.google.android.gms.nearby.exposurenotification.DiagnosisKeysDataMapping
+import com.google.android.gms.nearby.exposurenotification.ExposureNotificationClient
+import com.google.android.gms.nearby.exposurenotification.Infectiousness
+import com.google.android.gms.nearby.exposurenotification.ReportType
+import de.rki.coronawarnapp.nearby.modules.diagnosiskeysdatamapper.DefaultDiagnosisKeysDataMapper.Companion.hasChanged
+import io.kotest.matchers.shouldBe
+import io.mockk.MockKAnnotations
+import io.mockk.clearAllMocks
+import io.mockk.coEvery
+import io.mockk.impl.annotations.MockK
+import io.mockk.verify
+import org.junit.jupiter.api.AfterEach
+import org.junit.jupiter.api.BeforeEach
+import org.junit.jupiter.api.Test
+import testhelpers.BaseTest
+import testhelpers.coroutines.runBlockingTest2
+import testhelpers.gms.MockGMSTask
+
+class DefaultDiagnosisKeysDataMapperTest : BaseTest() {
+    @MockK lateinit var googleENFClient: ExposureNotificationClient
+
+    @BeforeEach
+    fun setup() {
+        MockKAnnotations.init(this)
+    }
+
+    @AfterEach
+    fun teardown() {
+        clearAllMocks()
+    }
+
+    private fun createMapper() = DefaultDiagnosisKeysDataMapper(
+        client = googleENFClient
+    )
+
+    @Test
+    fun `set mapping is invoked`() {
+        val firstMapping = DiagnosisKeysDataMapping.DiagnosisKeysDataMappingBuilder().apply {
+            setReportTypeWhenMissing(ReportType.CONFIRMED_TEST)
+            setInfectiousnessWhenDaysSinceOnsetMissing(Infectiousness.HIGH)
+            setDaysSinceOnsetToInfectiousness(mapOf(0 to Infectiousness.STANDARD, 1 to Infectiousness.HIGH))
+        }.build()
+
+        val secondMapping = DiagnosisKeysDataMapping.DiagnosisKeysDataMappingBuilder().apply {
+            setReportTypeWhenMissing(ReportType.CONFIRMED_TEST)
+            setInfectiousnessWhenDaysSinceOnsetMissing(Infectiousness.HIGH)
+            setDaysSinceOnsetToInfectiousness(mapOf(0 to Infectiousness.HIGH, 1 to Infectiousness.STANDARD))
+        }.build()
+
+        coEvery { googleENFClient.diagnosisKeysDataMapping } returns MockGMSTask.forValue(firstMapping)
+        coEvery { googleENFClient.setDiagnosisKeysDataMapping(any()) } returns MockGMSTask.forValue(null)
+
+        val mapper = createMapper()
+
+        runBlockingTest2 {
+            mapper.updateDiagnosisKeysDataMapping(secondMapping)
+        }
+
+        verify {
+            googleENFClient.setDiagnosisKeysDataMapping(secondMapping)
+        }
+    }
+
+    @Test
+    fun `set mapping is not invoked`() {
+        val firstMapping = DiagnosisKeysDataMapping.DiagnosisKeysDataMappingBuilder().apply {
+            setReportTypeWhenMissing(ReportType.CONFIRMED_TEST)
+            setInfectiousnessWhenDaysSinceOnsetMissing(Infectiousness.HIGH)
+            setDaysSinceOnsetToInfectiousness(mapOf(0 to Infectiousness.STANDARD, 1 to Infectiousness.HIGH))
+        }.build()
+
+        val secondMapping = DiagnosisKeysDataMapping.DiagnosisKeysDataMappingBuilder().apply {
+            setReportTypeWhenMissing(ReportType.CONFIRMED_TEST)
+            setInfectiousnessWhenDaysSinceOnsetMissing(Infectiousness.HIGH)
+            setDaysSinceOnsetToInfectiousness(mapOf(0 to Infectiousness.STANDARD, 1 to Infectiousness.HIGH))
+        }.build()
+
+        coEvery { googleENFClient.diagnosisKeysDataMapping } returns MockGMSTask.forValue(firstMapping)
+        coEvery { googleENFClient.setDiagnosisKeysDataMapping(any()) } returns MockGMSTask.forValue(null)
+
+        val mapper = createMapper()
+
+        runBlockingTest2 {
+            mapper.updateDiagnosisKeysDataMapping(secondMapping)
+        }
+
+        verify(exactly = 0) {
+            googleENFClient.setDiagnosisKeysDataMapping(secondMapping)
+        }
+    }
+
+    @Test
+    fun `mapping change detection works`() {
+        // Note that we cant create an empty mapping as the DiagnosisKeysDataMappingBuilder
+        // throws a IllegalArgumentException if one of the properties is missing
+        val nullMapping: DiagnosisKeysDataMapping? = null
+        val firstMapping = DiagnosisKeysDataMapping.DiagnosisKeysDataMappingBuilder().apply {
+            setReportTypeWhenMissing(ReportType.CONFIRMED_TEST)
+            setInfectiousnessWhenDaysSinceOnsetMissing(Infectiousness.HIGH)
+            setDaysSinceOnsetToInfectiousness(mapOf(0 to Infectiousness.STANDARD, 1 to Infectiousness.HIGH))
+        }.build()
+        val secondMapping = DiagnosisKeysDataMapping.DiagnosisKeysDataMappingBuilder().apply {
+            setReportTypeWhenMissing(ReportType.CONFIRMED_TEST)
+            setInfectiousnessWhenDaysSinceOnsetMissing(Infectiousness.HIGH)
+            setDaysSinceOnsetToInfectiousness(mapOf(0 to Infectiousness.HIGH, 1 to Infectiousness.STANDARD))
+        }.build()
+        val thirdMapping = DiagnosisKeysDataMapping.DiagnosisKeysDataMappingBuilder().apply {
+            setReportTypeWhenMissing(ReportType.CONFIRMED_TEST)
+            setInfectiousnessWhenDaysSinceOnsetMissing(Infectiousness.HIGH)
+            setDaysSinceOnsetToInfectiousness(mapOf())
+        }.build()
+        val fourthMapping = DiagnosisKeysDataMapping.DiagnosisKeysDataMappingBuilder().apply {
+            setReportTypeWhenMissing(ReportType.CONFIRMED_TEST)
+            setInfectiousnessWhenDaysSinceOnsetMissing(Infectiousness.HIGH)
+            setDaysSinceOnsetToInfectiousness(mapOf())
+        }.build()
+
+        firstMapping.hasChanged(nullMapping) shouldBe true
+        firstMapping.hasChanged(secondMapping) shouldBe true
+        firstMapping.hasChanged(thirdMapping) shouldBe true
+
+        secondMapping.hasChanged(nullMapping) shouldBe true
+        secondMapping.hasChanged(firstMapping) shouldBe true
+        secondMapping.hasChanged(thirdMapping) shouldBe true
+
+        thirdMapping.hasChanged(nullMapping) shouldBe true
+        thirdMapping.hasChanged(firstMapping) shouldBe true
+        thirdMapping.hasChanged(secondMapping) shouldBe true
+
+        nullMapping.hasChanged(nullMapping) shouldBe true
+        firstMapping.hasChanged(firstMapping) shouldBe false
+        secondMapping.hasChanged(secondMapping) shouldBe false
+        thirdMapping.hasChanged(thirdMapping) shouldBe false
+        thirdMapping.hasChanged(fourthMapping) shouldBe false
+    }
+}