diff --git a/lib/selectors/user-selectors.js b/lib/selectors/user-selectors.js
--- a/lib/selectors/user-selectors.js
+++ b/lib/selectors/user-selectors.js
@@ -71,16 +71,22 @@
     const username = userInfos[memberInfo.id]
       ? userInfos[memberInfo.id].username
       : null;
-    const { permissions, ...memberInfoSansPermissions } = memberInfo;
+    const { id, role, isSender, minimallyEncoded } = memberInfo;
     if (memberInfo.id === currentUserID) {
       relativeMemberInfos.unshift({
-        ...memberInfoSansPermissions,
+        id,
+        role,
+        isSender,
+        minimallyEncoded,
         username,
         isViewer: true,
       });
     } else {
       relativeMemberInfos.push({
-        ...memberInfoSansPermissions,
+        id,
+        role,
+        isSender,
+        minimallyEncoded,
         username,
         isViewer: false,
       });
diff --git a/lib/shared/redux/legacy-update-roles-and-permissions.js b/lib/shared/redux/legacy-update-roles-and-permissions.js
--- a/lib/shared/redux/legacy-update-roles-and-permissions.js
+++ b/lib/shared/redux/legacy-update-roles-and-permissions.js
@@ -14,6 +14,7 @@
   ThreadStoreThreadInfos,
   LegacyMemberInfo,
   MixedRawThreadInfos,
+  ThickMemberInfo,
 } from '../../types/thread-types.js';
 import { values } from '../../utils/objects.js';
 
@@ -51,6 +52,12 @@
   +[member: string]: ?ThreadPermissionsBlob,
 };
 
+type BaseMemberInfo = {
+  +id: string,
+  +role: ?string,
+  ...
+};
+
 // This migration utility can only be used with LegacyRawThreadInfos
 function legacyUpdateRolesAndPermissions(
   threadStoreInfos: MixedRawThreadInfos,
@@ -81,18 +88,19 @@
     node.children?.map(recursivelyUpdateRoles);
   };
 
-  const recursivelyUpdatePermissions = (
-    node: $ReadOnly<ThreadTraversalNode>,
+  const updateMembers = <T: BaseMemberInfo>(
+    threadInfo: LegacyRawThreadInfo,
+    members: $ReadOnlyArray<$ReadOnly<T>>,
     memberToThreadPermissionsFromParent: ?MemberToThreadPermissionsFromParent,
-  ): void => {
-    const threadInfo: LegacyRawThreadInfo =
-      updatedThreadStoreInfos[node.threadID];
-
+  ): {
+    members: $ReadOnlyArray<$ReadOnly<T>>,
+    memberToThreadPermissionsForChildren: { [string]: ?ThreadPermissionsBlob },
+  } => {
     const updatedMembers = [];
     const memberToThreadPermissionsForChildren: {
       [string]: ?ThreadPermissionsBlob,
     } = {};
-    for (const member: LegacyMemberInfo of threadInfo.members) {
+    for (const member of members) {
       const { id, role } = member;
 
       const rolePermissions = role ? threadInfo.roles[role].permissions : null;
@@ -116,11 +124,51 @@
       memberToThreadPermissionsForChildren[member.id] =
         makePermissionsForChildrenBlob(computedPermissions);
     }
-
-    updatedThreadStoreInfos[node.threadID] = {
-      ...threadInfo,
+    return {
       members: updatedMembers,
+      memberToThreadPermissionsForChildren,
     };
+  };
+
+  const recursivelyUpdatePermissions = (
+    node: $ReadOnly<ThreadTraversalNode>,
+    memberToThreadPermissionsFromParent: ?MemberToThreadPermissionsFromParent,
+  ): void => {
+    const threadInfo: LegacyRawThreadInfo =
+      updatedThreadStoreInfos[node.threadID];
+
+    let memberToThreadPermissionsForChildren: {
+      [string]: ?ThreadPermissionsBlob,
+    };
+    if (threadInfo.thick) {
+      const {
+        members: updatedMembers,
+        memberToThreadPermissionsForChildren: test,
+      } = updateMembers<ThickMemberInfo>(
+        threadInfo,
+        threadInfo.members,
+        memberToThreadPermissionsFromParent,
+      );
+      updatedThreadStoreInfos[node.threadID] = {
+        ...threadInfo,
+        members: updatedMembers,
+      };
+      memberToThreadPermissionsForChildren = test;
+    } else {
+      const {
+        members: updatedMembers,
+        memberToThreadPermissionsForChildren: test,
+      } = updateMembers<LegacyMemberInfo>(
+        threadInfo,
+        threadInfo.members,
+        memberToThreadPermissionsFromParent,
+      );
+      updatedThreadStoreInfos[node.threadID] = {
+        ...threadInfo,
+        members: updatedMembers,
+      };
+      memberToThreadPermissionsForChildren = test;
+    }
 
     node.children?.map(child =>
       recursivelyUpdatePermissions(child, memberToThreadPermissionsForChildren),
diff --git a/lib/shared/thread-utils.js b/lib/shared/thread-utils.js
--- a/lib/shared/thread-utils.js
+++ b/lib/shared/thread-utils.js
@@ -71,12 +71,15 @@
   threadTypes,
   threadTypeIsCommunityRoot,
   assertThreadType,
+  threadTypeIsThick,
+  assertThinThreadType,
+  assertThickThreadType,
 } from '../types/thread-types-enum.js';
 import type {
   LegacyRawThreadInfo,
   ClientLegacyRoleInfo,
   ServerThreadInfo,
-  ServerMemberInfo,
+  ThickMemberInfo,
   UserProfileThreadInfo,
   MixedRawThreadInfos,
   LegacyMemberInfo,
@@ -470,38 +473,84 @@
     specialRole: specialRoles.DEFAULT_ROLE,
   };
 
-  const rawThreadInfo: RawThreadInfo = {
-    minimallyEncoded: true,
-    id: threadID,
-    type: threadType,
-    name: name ?? null,
-    description: null,
-    color: threadColor ?? generatePendingThreadColor(memberIDs),
-    creationTime: now,
-    parentThreadID: parentThreadInfo?.id ?? null,
-    containingThreadID: getContainingThreadID(parentThreadInfo, threadType),
-    community: getCommunity(parentThreadInfo),
-    members: members.map(member =>
-      minimallyEncodeMemberInfo({
-        id: member.id,
+  let rawThreadInfo: RawThreadInfo;
+  if (threadTypeIsThick(threadType)) {
+    const thickThreadType = assertThickThreadType(threadType);
+    rawThreadInfo = {
+      minimallyEncoded: true,
+      thick: true,
+      id: threadID,
+      type: thickThreadType,
+      name: name ?? null,
+      description: null,
+      color: threadColor ?? generatePendingThreadColor(memberIDs),
+      creationTime: now,
+      parentThreadID: parentThreadInfo?.id ?? null,
+      containingThreadID: getContainingThreadID(
+        parentThreadInfo,
+        thickThreadType,
+      ),
+      community: getCommunity(parentThreadInfo),
+      members: members.map(member =>
+        minimallyEncodeMemberInfo<ThickMemberInfo>({
+          id: member.id,
+          role: role.id,
+          permissions: membershipPermissions,
+          isSender: false,
+          subscription: defaultSubscription,
+        }),
+      ),
+      roles: {
+        [role.id]: role,
+      },
+      currentUser: minimallyEncodeThreadCurrentUserInfo({
         role: role.id,
         permissions: membershipPermissions,
-        isSender: false,
+        subscription: defaultSubscription,
+        unread: false,
       }),
-    ),
-    roles: {
-      [role.id]: role,
-    },
-    currentUser: minimallyEncodeThreadCurrentUserInfo({
-      role: role.id,
-      permissions: membershipPermissions,
-      subscription: defaultSubscription,
-      unread: false,
-    }),
-    repliesCount: 0,
-    sourceMessageID,
-    pinnedCount: 0,
-  };
+      repliesCount: 0,
+      sourceMessageID,
+      pinnedCount: 0,
+    };
+  } else {
+    const thinThreadType = assertThinThreadType(threadType);
+    rawThreadInfo = {
+      minimallyEncoded: true,
+      id: threadID,
+      type: thinThreadType,
+      name: name ?? null,
+      description: null,
+      color: threadColor ?? generatePendingThreadColor(memberIDs),
+      creationTime: now,
+      parentThreadID: parentThreadInfo?.id ?? null,
+      containingThreadID: getContainingThreadID(
+        parentThreadInfo,
+        thinThreadType,
+      ),
+      community: getCommunity(parentThreadInfo),
+      members: members.map(member =>
+        minimallyEncodeMemberInfo<LegacyMemberInfo>({
+          id: member.id,
+          role: role.id,
+          permissions: membershipPermissions,
+          isSender: false,
+        }),
+      ),
+      roles: {
+        [role.id]: role,
+      },
+      currentUser: minimallyEncodeThreadCurrentUserInfo({
+        role: role.id,
+        permissions: membershipPermissions,
+        subscription: defaultSubscription,
+        unread: false,
+      }),
+      repliesCount: 0,
+      sourceMessageID,
+      pinnedCount: 0,
+    };
+  }
 
   const userInfos: { [string]: UserInfo } = {};
   for (const member of members) {
@@ -1024,7 +1073,9 @@
 // Since we don't have access to all of the ancestor ThreadInfos, we approximate
 // "parent admin" as anybody with CHANGE_ROLE permissions.
 function memberHasAdminPowers(
-  memberInfo: LegacyMemberInfo | MemberInfoWithPermissions | ServerMemberInfo,
+  memberInfo:
+    | { +minimallyEncoded: true, +permissions: string, ... }
+    | { +minimallyEncoded?: void, +permissions: ThreadPermissionsInfo, ... },
 ): boolean {
   if (memberInfo.minimallyEncoded) {
     return hasPermission(memberInfo.permissions, threadPermissions.CHANGE_ROLE);
diff --git a/lib/shared/updates/delete-account-spec.js b/lib/shared/updates/delete-account-spec.js
--- a/lib/shared/updates/delete-account-spec.js
+++ b/lib/shared/updates/delete-account-spec.js
@@ -25,19 +25,35 @@
     const operations = [];
     for (const threadID in storeThreadInfos) {
       const threadInfo = storeThreadInfos[threadID];
-      const newMembers = threadInfo.members.filter(
-        member => member.id !== update.deletedUserID,
-      );
-      if (newMembers.length < threadInfo.members.length) {
-        const updatedThread = {
-          ...threadInfo,
-          members: newMembers,
-        };
+
+      let replacedThreadInfo;
+      if (threadInfo.thick) {
+        const newMembers = threadInfo.members.filter(
+          member => member.id !== update.deletedUserID,
+        );
+        if (newMembers.length < threadInfo.members.length) {
+          replacedThreadInfo = {
+            ...threadInfo,
+            members: newMembers,
+          };
+        }
+      } else {
+        const newMembers = threadInfo.members.filter(
+          member => member.id !== update.deletedUserID,
+        );
+        if (newMembers.length < threadInfo.members.length) {
+          replacedThreadInfo = {
+            ...threadInfo,
+            members: newMembers,
+          };
+        }
+      }
+      if (replacedThreadInfo) {
         operations.push({
           type: 'replace',
           payload: {
-            id: threadID,
-            threadInfo: updatedThread,
+            id: threadInfo.id,
+            threadInfo: replacedThreadInfo,
           },
         });
       }
diff --git a/lib/types/minimally-encoded-thread-permissions-types.js b/lib/types/minimally-encoded-thread-permissions-types.js
--- a/lib/types/minimally-encoded-thread-permissions-types.js
+++ b/lib/types/minimally-encoded-thread-permissions-types.js
@@ -4,12 +4,16 @@
 import _mapValues from 'lodash/fp/mapValues.js';
 
 import type { ClientAvatar } from './avatar-types.js';
+import type { ThreadPermissionsInfo } from './thread-permission-types.js';
 import type { ThreadType } from './thread-types-enum.js';
 import type {
   LegacyMemberInfo,
   LegacyRawThreadInfo,
+  LegacyThinRawThreadInfo,
+  LegacyThickRawThreadInfo,
   ClientLegacyRoleInfo,
   LegacyThreadCurrentUserInfo,
+  ThickMemberInfo,
 } from './thread-types.js';
 import {
   decodeThreadRolePermissionsBitmaskArray,
@@ -117,9 +121,19 @@
   return rest;
 }
 
-const minimallyEncodeMemberInfo = (
-  memberInfo: LegacyMemberInfo,
-): MemberInfoWithPermissions => {
+export type MinimallyEncodedThickMemberInfo = $ReadOnly<{
+  ...ThickMemberInfo,
+  +minimallyEncoded: true,
+  +permissions: string,
+}>;
+
+const minimallyEncodeMemberInfo = <T: LegacyMemberInfo | ThickMemberInfo>(
+  memberInfo: T,
+): $ReadOnly<{
+  ...T,
+  +minimallyEncoded: true,
+  +permissions: string,
+}> => {
   invariant(
     !('minimallyEncoded' in memberInfo),
     'memberInfo is already minimally encoded.',
@@ -131,9 +145,20 @@
   };
 };
 
-const decodeMinimallyEncodedMemberInfo = (
-  minimallyEncodedMemberInfo: MemberInfoWithPermissions,
-): LegacyMemberInfo => {
+const decodeMinimallyEncodedMemberInfo = <
+  T: MemberInfoWithPermissions | MinimallyEncodedThickMemberInfo,
+>(
+  minimallyEncodedMemberInfo: T,
+): $ReadOnly<{
+  ...$Diff<
+    T,
+    {
+      +minimallyEncoded: true,
+      +permissions: string,
+    },
+  >,
+  +permissions: ThreadPermissionsInfo,
+}> => {
   const { minimallyEncoded, ...rest } = minimallyEncodedMemberInfo;
   return {
     ...rest,
@@ -143,23 +168,24 @@
   };
 };
 
-export type RelativeMemberInfo = {
-  +id: string,
-  +role: ?string,
-  +isSender: boolean,
+export type ThinRawThreadInfo = $ReadOnly<{
+  ...LegacyThinRawThreadInfo,
   +minimallyEncoded: true,
-  +username: ?string,
-  +isViewer: boolean,
-};
+  +members: $ReadOnlyArray<MemberInfoWithPermissions>,
+  +roles: { +[id: string]: RoleInfo },
+  +currentUser: ThreadCurrentUserInfo,
+}>;
 
-export type RawThreadInfo = $ReadOnly<{
-  ...LegacyRawThreadInfo,
+export type ThickRawThreadInfo = $ReadOnly<{
+  ...LegacyThickRawThreadInfo,
   +minimallyEncoded: true,
-  +members: $ReadOnlyArray<MemberInfoWithPermissions>,
+  +members: $ReadOnlyArray<MinimallyEncodedThickMemberInfo>,
   +roles: { +[id: string]: RoleInfo },
   +currentUser: ThreadCurrentUserInfo,
 }>;
 
+export type RawThreadInfo = ThinRawThreadInfo | ThickRawThreadInfo;
+
 const minimallyEncodeRawThreadInfo = (
   rawThreadInfo: LegacyRawThreadInfo,
 ): RawThreadInfo => {
@@ -167,27 +193,49 @@
     !('minimallyEncoded' in rawThreadInfo),
     'rawThreadInfo is already minimally encoded.',
   );
-  const { members, roles, currentUser, ...rest } = rawThreadInfo;
-  return {
-    ...rest,
-    minimallyEncoded: true,
-    members: members.map(minimallyEncodeMemberInfo),
-    roles: _mapValues(minimallyEncodeRoleInfo)(roles),
-    currentUser: minimallyEncodeThreadCurrentUserInfo(currentUser),
-  };
+  if (rawThreadInfo.thick) {
+    const { members, roles, currentUser, ...rest } = rawThreadInfo;
+    return {
+      ...rest,
+      minimallyEncoded: true,
+      members: members.map(minimallyEncodeMemberInfo),
+      roles: _mapValues(minimallyEncodeRoleInfo)(roles),
+      currentUser: minimallyEncodeThreadCurrentUserInfo(currentUser),
+    };
+  } else {
+    const { members, roles, currentUser, ...rest } = rawThreadInfo;
+    return {
+      ...rest,
+      minimallyEncoded: true,
+      members: members.map(minimallyEncodeMemberInfo),
+      roles: _mapValues(minimallyEncodeRoleInfo)(roles),
+      currentUser: minimallyEncodeThreadCurrentUserInfo(currentUser),
+    };
+  }
 };
 
 const decodeMinimallyEncodedRawThreadInfo = (
   minimallyEncodedRawThreadInfo: RawThreadInfo,
 ): LegacyRawThreadInfo => {
-  const { minimallyEncoded, members, roles, currentUser, ...rest } =
-    minimallyEncodedRawThreadInfo;
-  return {
-    ...rest,
-    members: members.map(decodeMinimallyEncodedMemberInfo),
-    roles: _mapValues(decodeMinimallyEncodedRoleInfo)(roles),
-    currentUser: decodeMinimallyEncodedThreadCurrentUserInfo(currentUser),
-  };
+  if (minimallyEncodedRawThreadInfo.thick) {
+    const { minimallyEncoded, members, roles, currentUser, ...rest } =
+      minimallyEncodedRawThreadInfo;
+    return {
+      ...rest,
+      members: members.map(decodeMinimallyEncodedMemberInfo),
+      roles: _mapValues(decodeMinimallyEncodedRoleInfo)(roles),
+      currentUser: decodeMinimallyEncodedThreadCurrentUserInfo(currentUser),
+    };
+  } else {
+    const { minimallyEncoded, members, roles, currentUser, ...rest } =
+      minimallyEncodedRawThreadInfo;
+    return {
+      ...rest,
+      members: members.map(decodeMinimallyEncodedMemberInfo),
+      roles: _mapValues(decodeMinimallyEncodedRoleInfo)(roles),
+      currentUser: decodeMinimallyEncodedThreadCurrentUserInfo(currentUser),
+    };
+  }
 };
 
 export type RoleInfoWithoutSpecialRole = $ReadOnly<{
@@ -200,6 +248,15 @@
   +roles: { +[id: string]: RoleInfoWithoutSpecialRole },
 }>;
 
+export type RelativeMemberInfo = {
+  +id: string,
+  +role: ?string,
+  +isSender: boolean,
+  +minimallyEncoded: true,
+  +username: ?string,
+  +isViewer: boolean,
+};
+
 export type ThreadInfo = $ReadOnly<{
   +minimallyEncoded: true,
   +id: string,
diff --git a/lib/types/thread-types.js b/lib/types/thread-types.js
--- a/lib/types/thread-types.js
+++ b/lib/types/thread-types.js
@@ -30,7 +30,12 @@
   threadRolePermissionsBlobValidator,
   type UserSurfacedPermission,
 } from './thread-permission-types.js';
-import { type ThreadType, threadTypeValidator } from './thread-types-enum.js';
+import {
+  type ThreadType,
+  type ThinThreadType,
+  type ThickThreadType,
+  threadTypeValidator,
+} from './thread-types-enum.js';
 import type { ClientUpdateInfo, ServerUpdateInfo } from './update-types.js';
 import type { UserInfo, UserInfos } from './user-types.js';
 import type { SpecialRole } from '../permissions/special-roles.js';
@@ -87,9 +92,9 @@
     unread: t.maybe(t.Boolean),
   });
 
-export type LegacyRawThreadInfo = {
+export type LegacyThinRawThreadInfo = {
   +id: string,
-  +type: ThreadType,
+  +type: ThinThreadType,
   +name: ?string,
   +avatar?: ?ClientAvatar,
   +description: ?string,
@@ -105,6 +110,39 @@
   +repliesCount: number,
   +pinnedCount?: number,
 };
+
+export type ThickMemberInfo = {
+  +id: string,
+  +role: ?string,
+  +permissions: ThreadPermissionsInfo,
+  +subscription: ThreadSubscription,
+  +isSender: boolean,
+};
+
+export type LegacyThickRawThreadInfo = {
+  +thick: true,
+  +id: string,
+  +type: ThickThreadType,
+  +name: ?string,
+  +avatar?: ?ClientAvatar,
+  +description: ?string,
+  +color: string, // hex, without "#" or "0x"
+  +creationTime: number, // millisecond timestamp
+  +parentThreadID: ?string,
+  +containingThreadID: ?string,
+  +community: ?string,
+  +members: $ReadOnlyArray<ThickMemberInfo>,
+  +roles: { +[id: string]: ClientLegacyRoleInfo },
+  +currentUser: LegacyThreadCurrentUserInfo,
+  +sourceMessageID?: string,
+  +repliesCount: number,
+  +pinnedCount?: number,
+};
+
+export type LegacyRawThreadInfo =
+  | LegacyThinRawThreadInfo
+  | LegacyThickRawThreadInfo;
+
 export type LegacyRawThreadInfos = {
   +[id: string]: LegacyRawThreadInfo,
 };
diff --git a/lib/utils/thread-ops-utils.js b/lib/utils/thread-ops-utils.js
--- a/lib/utils/thread-ops-utils.js
+++ b/lib/utils/thread-ops-utils.js
@@ -8,7 +8,6 @@
   threadCurrentUserInfoValidator,
 } from '../permissions/minimally-encoded-raw-thread-info-validators.js';
 import type {
-  MemberInfoWithPermissions,
   RawThreadInfo,
   RoleInfo,
 } from '../types/minimally-encoded-thread-permissions-types.js';
@@ -18,7 +17,12 @@
   minimallyEncodeRoleInfo,
   minimallyEncodeThreadCurrentUserInfo,
 } from '../types/minimally-encoded-thread-permissions-types.js';
-import { assertThreadType } from '../types/thread-types-enum.js';
+import {
+  assertThreadType,
+  threadTypeIsThick,
+  assertThinThreadType,
+  assertThickThreadType,
+} from '../types/thread-types-enum.js';
 import {
   type ClientDBThreadInfo,
   legacyMemberInfoValidator,
@@ -30,7 +34,7 @@
 function convertRawThreadInfoToClientDBThreadInfo(
   rawThreadInfo: LegacyRawThreadInfo | RawThreadInfo,
 ): ClientDBThreadInfo {
-  const { minimallyEncoded, ...rest } = rawThreadInfo;
+  const { minimallyEncoded, thick, ...rest } = rawThreadInfo;
   return {
     ...rest,
     creationTime: rawThreadInfo.creationTime.toString(),
@@ -46,17 +50,18 @@
 ): RawThreadInfo {
   // 1. Validate and potentially minimally encode `rawMembers`.
   const rawMembers = JSON.parse(clientDBThreadInfo.members);
-  const minimallyEncodedMembers: $ReadOnlyArray<MemberInfoWithPermissions> =
-    rawMembers.map(rawMember => {
-      invariant(
-        memberInfoWithPermissionsValidator.is(rawMember) ||
-          legacyMemberInfoValidator.is(rawMember),
-        'rawMember must be valid [MinimallyEncoded/Legacy]MemberInfo',
-      );
-      return rawMember.minimallyEncoded
-        ? rawMember
-        : minimallyEncodeMemberInfo(rawMember);
-    });
+  const minimallyEncodedMembers = rawMembers.map(rawMember => {
+    invariant(
+      // TODO these must be updated to accept new client-only change
+      //      that subscription field may be present
+      memberInfoWithPermissionsValidator.is(rawMember) ||
+        legacyMemberInfoValidator.is(rawMember),
+      'rawMember must be valid [MinimallyEncoded/Legacy]MemberInfo',
+    );
+    return rawMember.minimallyEncoded
+      ? rawMember
+      : minimallyEncodeMemberInfo(rawMember);
+  });
 
   // 2. Validate and potentially minimally encode `rawRoles`.
   const rawRoles = JSON.parse(clientDBThreadInfo.roles);
@@ -86,23 +91,48 @@
     ? rawCurrentUser
     : minimallyEncodeThreadCurrentUserInfo(rawCurrentUser);
 
-  let rawThreadInfo: RawThreadInfo = {
-    minimallyEncoded: true,
-    id: clientDBThreadInfo.id,
-    type: assertThreadType(clientDBThreadInfo.type),
-    name: clientDBThreadInfo.name,
-    description: clientDBThreadInfo.description,
-    color: clientDBThreadInfo.color,
-    creationTime: Number(clientDBThreadInfo.creationTime),
-    parentThreadID: clientDBThreadInfo.parentThreadID,
-    containingThreadID: clientDBThreadInfo.containingThreadID,
-    community: clientDBThreadInfo.community,
-    members: minimallyEncodedMembers,
-    roles: minimallyEncodedRoles,
-    currentUser: minimallyEncodedCurrentUser,
-    repliesCount: clientDBThreadInfo.repliesCount,
-    pinnedCount: clientDBThreadInfo.pinnedCount,
-  };
+  let rawThreadInfo: RawThreadInfo;
+  const threadType = assertThreadType(clientDBThreadInfo.type);
+  if (threadTypeIsThick(threadType)) {
+    const thickThreadType = assertThickThreadType(threadType);
+    rawThreadInfo = {
+      minimallyEncoded: true,
+      thick: true,
+      id: clientDBThreadInfo.id,
+      type: thickThreadType,
+      name: clientDBThreadInfo.name,
+      description: clientDBThreadInfo.description,
+      color: clientDBThreadInfo.color,
+      creationTime: Number(clientDBThreadInfo.creationTime),
+      parentThreadID: clientDBThreadInfo.parentThreadID,
+      containingThreadID: clientDBThreadInfo.containingThreadID,
+      community: clientDBThreadInfo.community,
+      members: minimallyEncodedMembers,
+      roles: minimallyEncodedRoles,
+      currentUser: minimallyEncodedCurrentUser,
+      repliesCount: clientDBThreadInfo.repliesCount,
+      pinnedCount: clientDBThreadInfo.pinnedCount,
+    };
+  } else {
+    const thinThreadType = assertThinThreadType(threadType);
+    rawThreadInfo = {
+      minimallyEncoded: true,
+      id: clientDBThreadInfo.id,
+      type: thinThreadType,
+      name: clientDBThreadInfo.name,
+      description: clientDBThreadInfo.description,
+      color: clientDBThreadInfo.color,
+      creationTime: Number(clientDBThreadInfo.creationTime),
+      parentThreadID: clientDBThreadInfo.parentThreadID,
+      containingThreadID: clientDBThreadInfo.containingThreadID,
+      community: clientDBThreadInfo.community,
+      members: minimallyEncodedMembers,
+      roles: minimallyEncodedRoles,
+      currentUser: minimallyEncodedCurrentUser,
+      repliesCount: clientDBThreadInfo.repliesCount,
+      pinnedCount: clientDBThreadInfo.pinnedCount,
+    };
+  }
 
   if (clientDBThreadInfo.sourceMessageID) {
     rawThreadInfo = {
diff --git a/native/redux/edit-thread-permission-migration.js b/native/redux/edit-thread-permission-migration.js
--- a/native/redux/edit-thread-permission-migration.js
+++ b/native/redux/edit-thread-permission-migration.js
@@ -7,10 +7,11 @@
   ClientLegacyRoleInfo,
   LegacyRawThreadInfos,
   LegacyThreadCurrentUserInfo,
+  ThickMemberInfo,
 } from 'lib/types/thread-types.js';
 
 function addDetailedThreadEditPermissionsToUser<
-  T: LegacyMemberInfo | LegacyThreadCurrentUserInfo,
+  T: LegacyMemberInfo | LegacyThreadCurrentUserInfo | ThickMemberInfo,
 >(threadInfo: LegacyRawThreadInfo, member: T, threadID: string): T {
   let newPermissions = null;
   if (threadInfo.type === threadTypes.GENESIS_PRIVATE) {
@@ -64,10 +65,6 @@
   const newThreadInfos: { [string]: LegacyRawThreadInfo } = {};
   for (const threadID in threadInfos) {
     const threadInfo: LegacyRawThreadInfo = threadInfos[threadID];
-    const updatedMembers = threadInfo.members.map(member =>
-      addDetailedThreadEditPermissionsToUser(threadInfo, member, threadID),
-    );
-
     const updatedCurrentUser = addDetailedThreadEditPermissionsToUser(
       threadInfo,
       threadInfo.currentUser,
@@ -82,13 +79,29 @@
       );
     }
 
-    const newThreadInfo = {
-      ...threadInfo,
-      members: updatedMembers,
-      currentUser: updatedCurrentUser,
-      roles: updatedRoles,
-    };
-    newThreadInfos[threadID] = newThreadInfo;
+    if (threadInfo.thick) {
+      const updatedMembers = threadInfo.members.map(member =>
+        addDetailedThreadEditPermissionsToUser(threadInfo, member, threadID),
+      );
+      const newThreadInfo = {
+        ...threadInfo,
+        members: updatedMembers,
+        currentUser: updatedCurrentUser,
+        roles: updatedRoles,
+      };
+      newThreadInfos[threadID] = newThreadInfo;
+    } else {
+      const updatedMembers = threadInfo.members.map(member =>
+        addDetailedThreadEditPermissionsToUser(threadInfo, member, threadID),
+      );
+      const newThreadInfo = {
+        ...threadInfo,
+        members: updatedMembers,
+        currentUser: updatedCurrentUser,
+        roles: updatedRoles,
+      };
+      newThreadInfos[threadID] = newThreadInfo;
+    }
   }
   return newThreadInfos;
 }
diff --git a/native/redux/manage-pins-permission-migration.js b/native/redux/manage-pins-permission-migration.js
--- a/native/redux/manage-pins-permission-migration.js
+++ b/native/redux/manage-pins-permission-migration.js
@@ -6,6 +6,7 @@
   LegacyThreadCurrentUserInfo,
   ClientLegacyRoleInfo,
   LegacyRawThreadInfos,
+  ThickMemberInfo,
 } from 'lib/types/thread-types.js';
 
 type ThreadStoreThreadInfos = LegacyRawThreadInfos;
@@ -13,7 +14,10 @@
 const adminRoleName = 'Admins';
 
 function addManagePinsThreadPermissionToUser<
-  TargetMemberInfo: LegacyMemberInfo | LegacyThreadCurrentUserInfo,
+  TargetMemberInfo:
+    | LegacyMemberInfo
+    | LegacyThreadCurrentUserInfo
+    | ThickMemberInfo,
 >(
   threadInfo: LegacyRawThreadInfo,
   member: TargetMemberInfo,
@@ -62,10 +66,6 @@
   const newThreadInfos: { [string]: LegacyRawThreadInfo } = {};
   for (const threadID in threadInfos) {
     const threadInfo: LegacyRawThreadInfo = threadInfos[threadID];
-    const updatedMembers = threadInfo.members.map(member =>
-      addManagePinsThreadPermissionToUser(threadInfo, member, threadID),
-    );
-
     const updatedCurrentUser = addManagePinsThreadPermissionToUser(
       threadInfo,
       threadInfo.currentUser,
@@ -79,13 +79,29 @@
       );
     }
 
-    const updatedThreadInfo = {
-      ...threadInfo,
-      members: updatedMembers,
-      currentUser: updatedCurrentUser,
-      roles: updatedRoles,
-    };
-    newThreadInfos[threadID] = updatedThreadInfo;
+    if (threadInfo.thick) {
+      const updatedMembers = threadInfo.members.map(member =>
+        addManagePinsThreadPermissionToUser(threadInfo, member, threadID),
+      );
+      const updatedThreadInfo = {
+        ...threadInfo,
+        members: updatedMembers,
+        currentUser: updatedCurrentUser,
+        roles: updatedRoles,
+      };
+      newThreadInfos[threadID] = updatedThreadInfo;
+    } else {
+      const updatedMembers = threadInfo.members.map(member =>
+        addManagePinsThreadPermissionToUser(threadInfo, member, threadID),
+      );
+      const updatedThreadInfo = {
+        ...threadInfo,
+        members: updatedMembers,
+        currentUser: updatedCurrentUser,
+        roles: updatedRoles,
+      };
+      newThreadInfos[threadID] = updatedThreadInfo;
+    }
   }
   return newThreadInfos;
 }