diff --git a/app/src/main/java/org/thoughtcrime/securesms/database/RecipientDatabase.java b/app/src/main/java/org/thoughtcrime/securesms/database/RecipientDatabase.java
index 033d780c13f2fede1fc86f8ec2b4947245ef9836..0f8763e573dae21371173a1baff87b6842dddf2f 100644
--- a/app/src/main/java/org/thoughtcrime/securesms/database/RecipientDatabase.java
+++ b/app/src/main/java/org/thoughtcrime/securesms/database/RecipientDatabase.java
@@ -2716,12 +2716,16 @@ public class RecipientDatabase extends Database {
     ApplicationDependencies.getRecipientCache().clear();
   }
 
-  public void updateStorageKeys(@NonNull Map<RecipientId, byte[]> keys) {
+  public void updateStorageId(@NonNull RecipientId recipientId, byte[] id) {
+    updateStorageIds(Collections.singletonMap(recipientId, id));
+  }
+
+  public void updateStorageIds(@NonNull Map<RecipientId, byte[]> ids) {
     SQLiteDatabase db = databaseHelper.getWritableDatabase();
     db.beginTransaction();
 
     try {
-      for (Map.Entry<RecipientId, byte[]> entry : keys.entrySet()) {
+      for (Map.Entry<RecipientId, byte[]> entry : ids.entrySet()) {
         ContentValues values = new ContentValues();
         values.put(STORAGE_SERVICE_ID, Base64.encodeBytes(entry.getValue()));
         db.update(TABLE_NAME, values, ID_WHERE, new String[] { entry.getKey().serialize() });
@@ -2732,7 +2736,7 @@ public class RecipientDatabase extends Database {
       db.endTransaction();
     }
 
-    for (RecipientId id : keys.keySet()) {
+    for (RecipientId id : ids.keySet()) {
       Recipient.live(id).refresh();
     }
   }
diff --git a/app/src/main/java/org/thoughtcrime/securesms/jobs/StorageSyncJob.java b/app/src/main/java/org/thoughtcrime/securesms/jobs/StorageSyncJob.java
index 8a3a7e897c05c0422b04b3159568054a0a6f69e4..3a394c01de06be794a583bafd9c7a336e3f9f769 100644
--- a/app/src/main/java/org/thoughtcrime/securesms/jobs/StorageSyncJob.java
+++ b/app/src/main/java/org/thoughtcrime/securesms/jobs/StorageSyncJob.java
@@ -279,7 +279,7 @@ public class StorageSyncJob extends BaseJob {
       clearIds.add(Recipient.self().getId());
 
       recipientDatabase.clearDirtyState(clearIds);
-      recipientDatabase.updateStorageKeys(localWriteResult.get().getStorageKeyUpdates());
+      recipientDatabase.updateStorageIds(localWriteResult.get().getStorageKeyUpdates());
 
       needsMultiDeviceSync = true;
 
diff --git a/app/src/main/java/org/thoughtcrime/securesms/jobs/StorageSyncJobV2.java b/app/src/main/java/org/thoughtcrime/securesms/jobs/StorageSyncJobV2.java
index 5a7f455d4b67813a6f4084bacfe14a6e3c89c541..3c8f8e56f6dd70dd0a4a319aa9ac0f7885101080 100644
--- a/app/src/main/java/org/thoughtcrime/securesms/jobs/StorageSyncJobV2.java
+++ b/app/src/main/java/org/thoughtcrime/securesms/jobs/StorageSyncJobV2.java
@@ -395,7 +395,7 @@ public class StorageSyncJobV2 extends BaseJob {
       clearIds.add(Recipient.self().getId());
 
       recipientDatabase.clearDirtyState(clearIds);
-      recipientDatabase.updateStorageKeys(localWriteResult.get().getStorageKeyUpdates());
+      recipientDatabase.updateStorageIds(localWriteResult.get().getStorageKeyUpdates());
 
       needsMultiDeviceSync = true;
 
diff --git a/app/src/main/java/org/thoughtcrime/securesms/storage/AccountRecordProcessor.java b/app/src/main/java/org/thoughtcrime/securesms/storage/AccountRecordProcessor.java
index 3d405f35d69920912ea21f04cb94a5659113d669..3305167e9b171d928957e9c4e8e865ea545dcb2b 100644
--- a/app/src/main/java/org/thoughtcrime/securesms/storage/AccountRecordProcessor.java
+++ b/app/src/main/java/org/thoughtcrime/securesms/storage/AccountRecordProcessor.java
@@ -9,19 +9,14 @@ import org.signal.core.util.logging.Log;
 import org.thoughtcrime.securesms.database.DatabaseFactory;
 import org.thoughtcrime.securesms.database.RecipientDatabase;
 import org.thoughtcrime.securesms.recipients.Recipient;
-import org.thoughtcrime.securesms.recipients.RecipientId;
 import org.whispersystems.libsignal.util.guava.Optional;
 import org.whispersystems.signalservice.api.storage.SignalAccountRecord;
 import org.whispersystems.signalservice.api.storage.SignalAccountRecord.PinnedConversation;
-import org.whispersystems.signalservice.api.storage.StorageId;
 import org.whispersystems.signalservice.internal.storage.protos.AccountRecord;
 
 import java.util.Arrays;
-import java.util.Collection;
-import java.util.HashSet;
 import java.util.List;
 import java.util.Objects;
-import java.util.Set;
 
 /**
  * Processes {@link SignalAccountRecord}s. Unlike some other {@link StorageRecordProcessor}s, this
@@ -66,7 +61,7 @@ public class AccountRecordProcessor extends DefaultStorageRecordProcessor<Signal
   }
 
   @Override
-  public @NonNull Optional<SignalAccountRecord> getMatching(@NonNull SignalAccountRecord record) {
+  public @NonNull Optional<SignalAccountRecord> getMatching(@NonNull SignalAccountRecord record, @NonNull StorageKeyGenerator keyGenerator) {
     return Optional.of(localAccountRecord);
   }
 
diff --git a/app/src/main/java/org/thoughtcrime/securesms/storage/ContactRecordProcessor.java b/app/src/main/java/org/thoughtcrime/securesms/storage/ContactRecordProcessor.java
index 71c73eacf9f7dc8cf3bc84efb4b65b4f0ff67e9e..c2ec660412e9c36080de7e1e477b8fb4a4a48c52 100644
--- a/app/src/main/java/org/thoughtcrime/securesms/storage/ContactRecordProcessor.java
+++ b/app/src/main/java/org/thoughtcrime/securesms/storage/ContactRecordProcessor.java
@@ -16,9 +16,6 @@ import org.whispersystems.signalservice.api.storage.SignalContactRecord;
 import org.whispersystems.signalservice.internal.storage.protos.ContactRecord.IdentityState;
 
 import java.util.Arrays;
-import java.util.Collection;
-import java.util.LinkedList;
-import java.util.List;
 import java.util.Objects;
 import java.util.UUID;
 
@@ -63,13 +60,21 @@ public class ContactRecordProcessor extends DefaultStorageRecordProcessor<Signal
   }
 
   @Override
-  @NonNull Optional<SignalContactRecord> getMatching(@NonNull SignalContactRecord remote) {
+  @NonNull Optional<SignalContactRecord> getMatching(@NonNull SignalContactRecord remote, @NonNull StorageKeyGenerator keyGenerator) {
     SignalServiceAddress  address = remote.getAddress();
     Optional<RecipientId> byUuid  = address.getUuid().isPresent() ? recipientDatabase.getByUuid(address.getUuid().get()) : Optional.absent();
     Optional<RecipientId> byE164  = address.getNumber().isPresent() ? recipientDatabase.getByE164(address.getNumber().get()) : Optional.absent();
 
     return byUuid.or(byE164).transform(recipientDatabase::getRecipientSettingsForSync)
-                            .transform(StorageSyncModels::localToRemoteRecord)
+                            .transform(settings -> {
+                              if (settings.getStorageId() != null) {
+                                return StorageSyncModels.localToRemoteRecord(settings);
+                              } else {
+                                Log.w(TAG, "Newly discovering a registered user via storage service. Saving a storageId for them.");
+                                recipientDatabase.updateStorageId(settings.getId(), keyGenerator.generate());
+                                return StorageSyncModels.localToRemoteRecord(recipientDatabase.getRecipientSettingsForSync(settings.getId()));
+                              }
+                            })
                             .transform(r -> r.getContact().get());
   }
 
diff --git a/app/src/main/java/org/thoughtcrime/securesms/storage/DefaultStorageRecordProcessor.java b/app/src/main/java/org/thoughtcrime/securesms/storage/DefaultStorageRecordProcessor.java
index e2a4beb61037adf5b55e382f51bb0bf2bf83dd07..2cc3b13325f78be648aeca44648ad63a8a4007ab 100644
--- a/app/src/main/java/org/thoughtcrime/securesms/storage/DefaultStorageRecordProcessor.java
+++ b/app/src/main/java/org/thoughtcrime/securesms/storage/DefaultStorageRecordProcessor.java
@@ -51,7 +51,7 @@ abstract class DefaultStorageRecordProcessor<E extends SignalRecord> implements
       if (isInvalid(remote)) {
         remoteDeletes.add(remote);
       } else {
-        Optional<E> local = getMatching(remote);
+        Optional<E> local = getMatching(remote, keyGenerator);
 
         if (local.isPresent()) {
           E merged = merge(remote, local.get(), keyGenerator);
@@ -88,7 +88,7 @@ abstract class DefaultStorageRecordProcessor<E extends SignalRecord> implements
    * Only records that pass the validity check (i.e. return false from {@link #isInvalid(SignalRecord)}
    * make it to here, so you can assume all records are valid.
    */
-  abstract @NonNull Optional<E> getMatching(@NonNull E remote);
+  abstract @NonNull Optional<E> getMatching(@NonNull E remote, @NonNull StorageKeyGenerator keyGenerator);
 
   abstract @NonNull E merge(@NonNull E remote, @NonNull E local, @NonNull StorageKeyGenerator keyGenerator);
   abstract void insertLocal(@NonNull E record) throws IOException;
diff --git a/app/src/main/java/org/thoughtcrime/securesms/storage/GroupV1RecordProcessor.java b/app/src/main/java/org/thoughtcrime/securesms/storage/GroupV1RecordProcessor.java
index a3f99104e444f89e319ce8b45fba88027c44358d..8b5d57afe21ed07282742c0060d0b2b8e752efc7 100644
--- a/app/src/main/java/org/thoughtcrime/securesms/storage/GroupV1RecordProcessor.java
+++ b/app/src/main/java/org/thoughtcrime/securesms/storage/GroupV1RecordProcessor.java
@@ -14,8 +14,6 @@ import org.thoughtcrime.securesms.groups.GroupId;
 import org.thoughtcrime.securesms.recipients.RecipientId;
 import org.whispersystems.libsignal.util.guava.Optional;
 import org.whispersystems.signalservice.api.storage.SignalGroupV1Record;
-import org.whispersystems.signalservice.api.storage.SignalGroupV2Record;
-import org.whispersystems.signalservice.api.storage.SignalStorageRecord;
 
 import java.util.Arrays;
 
@@ -64,7 +62,7 @@ public final class GroupV1RecordProcessor extends DefaultStorageRecordProcessor<
   }
 
   @Override
-  @NonNull Optional<SignalGroupV1Record> getMatching(@NonNull SignalGroupV1Record record) {
+  @NonNull Optional<SignalGroupV1Record> getMatching(@NonNull SignalGroupV1Record record, @NonNull StorageKeyGenerator keyGenerator) {
     GroupId.V1 groupId = GroupId.v1orThrow(record.getGroupId());
 
     Optional<RecipientId> recipientId = recipientDatabase.getByGroupId(groupId);
diff --git a/app/src/main/java/org/thoughtcrime/securesms/storage/GroupV2RecordProcessor.java b/app/src/main/java/org/thoughtcrime/securesms/storage/GroupV2RecordProcessor.java
index 8b65dbcb190ba4c6fa5f78a087f2d5754bf7469c..13ea8c9d4024dbe425211653b945856293b0d6b9 100644
--- a/app/src/main/java/org/thoughtcrime/securesms/storage/GroupV2RecordProcessor.java
+++ b/app/src/main/java/org/thoughtcrime/securesms/storage/GroupV2RecordProcessor.java
@@ -13,10 +13,8 @@ import org.thoughtcrime.securesms.database.RecipientDatabase;
 import org.thoughtcrime.securesms.groups.GroupId;
 import org.thoughtcrime.securesms.groups.GroupsV1MigrationUtil;
 import org.thoughtcrime.securesms.recipients.RecipientId;
-import org.thoughtcrime.securesms.util.ParcelUtil;
 import org.whispersystems.libsignal.util.guava.Optional;
 import org.whispersystems.signalservice.api.storage.SignalGroupV2Record;
-import org.whispersystems.signalservice.internal.storage.protos.GroupV2Record;
 
 import java.io.IOException;
 import java.util.Arrays;
@@ -46,7 +44,7 @@ public final class GroupV2RecordProcessor extends DefaultStorageRecordProcessor<
   }
 
   @Override
-  @NonNull Optional<SignalGroupV2Record> getMatching(@NonNull SignalGroupV2Record record) {
+  @NonNull Optional<SignalGroupV2Record> getMatching(@NonNull SignalGroupV2Record record, @NonNull StorageKeyGenerator keyGenerator) {
     GroupId.V2 groupId = GroupId.v2(record.getMasterKeyOrThrow());
 
     Optional<RecipientId> recipientId = recipientDatabase.getByGroupId(groupId);