diff --git a/keyserver/src/creators/thread-creator.js b/keyserver/src/creators/thread-creator.js
--- a/keyserver/src/creators/thread-creator.js
+++ b/keyserver/src/creators/thread-creator.js
@@ -11,7 +11,6 @@
 } from 'lib/shared/color-utils.js';
 import { isInvalidSidebarSource } from 'lib/shared/message-utils.js';
 import { getThreadTypeParentRequirement } from 'lib/shared/thread-utils.js';
-import type { Shape } from 'lib/types/core.js';
 import { messageTypes } from 'lib/types/message-types-enum.js';
 import type { RawMessageInfo, MessageData } from 'lib/types/message-types.js';
 import { threadPermissions } from 'lib/types/thread-permission-types.js';
@@ -64,7 +63,7 @@
   'This is your private chat, ' +
   'where you can set reminders and jot notes in private!';
 
-type CreateThreadOptions = Shape<{
+type CreateThreadOptions = Partial<{
   +forceAddMembers: boolean,
   +updatesForCurrentSession: UpdatesForCurrentSession,
   +silentlyFailMembers: boolean,
diff --git a/keyserver/src/scripts/merge-users.js b/keyserver/src/scripts/merge-users.js
--- a/keyserver/src/scripts/merge-users.js
+++ b/keyserver/src/scripts/merge-users.js
@@ -1,6 +1,5 @@
 // @flow
 
-import type { Shape } from 'lib/types/core.js';
 import type { ServerThreadInfo } from 'lib/types/thread-types.js';
 import { updateTypes } from 'lib/types/update-types-enum.js';
 import { type UpdateData } from 'lib/types/update-types.js';
@@ -29,7 +28,7 @@
   }
 }
 
-type ReplaceUserInfo = Shape<{
+type ReplaceUserInfo = Partial<{
   +username: boolean,
   +password: boolean,
 }>;
diff --git a/keyserver/src/session/cookies.js b/keyserver/src/session/cookies.js
--- a/keyserver/src/session/cookies.js
+++ b/keyserver/src/session/cookies.js
@@ -7,7 +7,6 @@
 
 import { isStaff } from 'lib/shared/staff-utils.js';
 import { hasMinCodeVersion } from 'lib/shared/version-utils.js';
-import type { Shape } from 'lib/types/core.js';
 import type { SignedIdentityKeysBlob } from 'lib/types/crypto-types.js';
 import type { Platform, PlatformDetails } from 'lib/types/device-types.js';
 import type { CalendarQuery } from 'lib/types/entry-types.js';
@@ -493,7 +492,7 @@
   result.cookieChange = sessionChange;
 }
 
-type AnonymousCookieCreationParams = Shape<{
+type AnonymousCookieCreationParams = Partial<{
   +platformDetails: ?PlatformDetails,
   +deviceToken: ?string,
 }>;
diff --git a/keyserver/src/socket/socket.js b/keyserver/src/socket/socket.js
--- a/keyserver/src/socket/socket.js
+++ b/keyserver/src/socket/socket.js
@@ -16,7 +16,6 @@
 } from 'lib/shared/timeouts.js';
 import { mostRecentUpdateTimestamp } from 'lib/shared/update-utils.js';
 import { hasMinCodeVersion } from 'lib/shared/version-utils.js';
-import type { Shape } from 'lib/types/core.js';
 import { endpointIsSocketSafe } from 'lib/types/endpoints.js';
 import type { RawEntryInfo } from 'lib/types/entry-types.js';
 import { defaultNumberPerThread } from 'lib/types/message-types.js';
@@ -829,7 +828,7 @@
     }
   }
 
-  setStateCheckConditions(newConditions: Shape<StateCheckConditions>) {
+  setStateCheckConditions(newConditions: Partial<StateCheckConditions>) {
     this.stateCheckConditions = {
       ...this.stateCheckConditions,
       ...newConditions,
diff --git a/keyserver/src/updaters/session-updaters.js b/keyserver/src/updaters/session-updaters.js
--- a/keyserver/src/updaters/session-updaters.js
+++ b/keyserver/src/updaters/session-updaters.js
@@ -1,12 +1,11 @@
 // @flow
 
-import type { Shape } from 'lib/types/core.js';
 import type { CalendarQuery } from 'lib/types/entry-types.js';
 
 import { dbQuery, SQL } from '../database/database.js';
 import type { Viewer } from '../session/viewer.js';
 
-export type SessionUpdate = Shape<{
+export type SessionUpdate = Partial<{
   +query: CalendarQuery,
   +lastUpdate: number,
   +lastValidated: number,
diff --git a/keyserver/src/updaters/thread-updaters.js b/keyserver/src/updaters/thread-updaters.js
--- a/keyserver/src/updaters/thread-updaters.js
+++ b/keyserver/src/updaters/thread-updaters.js
@@ -10,7 +10,6 @@
   viewerIsMember,
   getThreadTypeParentRequirement,
 } from 'lib/shared/thread-utils.js';
-import type { Shape } from 'lib/types/core.js';
 import { messageTypes } from 'lib/types/message-types-enum.js';
 import type { RawMessageInfo, MessageData } from 'lib/types/message-types.js';
 import { threadPermissions } from 'lib/types/thread-permission-types.js';
@@ -324,7 +323,7 @@
   return { updatesResult: { newUpdates: viewerUpdates } };
 }
 
-type UpdateThreadOptions = Shape<{
+type UpdateThreadOptions = Partial<{
   +forceAddMembers: boolean,
   +forceUpdateRoot: boolean,
   +silenceMessages: boolean,
diff --git a/lib/hooks/theme.js b/lib/hooks/theme.js
--- a/lib/hooks/theme.js
+++ b/lib/hooks/theme.js
@@ -3,7 +3,6 @@
 import * as React from 'react';
 
 import { updateThemeInfoActionType } from '../actions/theme-actions.js';
-import type { Shape } from '../types/core.js';
 import type {
   GlobalTheme,
   GlobalThemeInfo,
@@ -21,7 +20,7 @@
         return;
       }
 
-      let updateObject: Shape<GlobalThemeInfo> = {
+      let updateObject: Partial<GlobalThemeInfo> = {
         systemTheme: colorScheme,
       };
       if (globalThemeInfo.preference === 'system') {
diff --git a/lib/media/file-utils.js b/lib/media/file-utils.js
--- a/lib/media/file-utils.js
+++ b/lib/media/file-utils.js
@@ -3,7 +3,6 @@
 import fileType from 'file-type';
 import invariant from 'invariant';
 
-import type { Shape } from '../types/core.js';
 import type { MediaType } from '../types/media-types.js';
 
 type ResultMIME = 'image/png' | 'image/jpeg';
@@ -12,10 +11,10 @@
   +extension: string,
   +serverCanHandle: boolean,
   +serverTranscodesImage: boolean,
-  +imageConfig?: Shape<{
+  +imageConfig?: Partial<{
     +convertTo: ResultMIME,
   }>,
-  +videoConfig?: Shape<{
+  +videoConfig?: Partial<{
     +loop: boolean,
   }>,
 };
diff --git a/lib/types/core.js b/lib/types/core.js
deleted file mode 100644
--- a/lib/types/core.js
+++ /dev/null
@@ -1,3 +0,0 @@
-// @flow
-
-export type Shape<O> = $ReadOnly<$Rest<O, { ... }>>;
diff --git a/lib/types/media-types.js b/lib/types/media-types.js
--- a/lib/types/media-types.js
+++ b/lib/types/media-types.js
@@ -3,7 +3,6 @@
 import t, { type TInterface, type TUnion } from 'tcomb';
 
 import type { ClientEncryptedImageAvatar } from './avatar-types';
-import type { Shape } from './core.js';
 import { type Platform } from './device-types.js';
 import { tShape, tString, tID } from '../utils/validation-utils.js';
 
@@ -36,7 +35,7 @@
   +extras: string,
 };
 
-export type Corners = Shape<{
+export type Corners = Partial<{
   +topLeft: boolean,
   +topRight: boolean,
   +bottomLeft: boolean,
@@ -767,10 +766,10 @@
 
 export type Media = Image | Video | EncryptedImage | EncryptedVideo;
 export type MediaShape =
-  | Shape<Image>
-  | Shape<Video>
-  | Shape<EncryptedImage>
-  | Shape<EncryptedVideo>;
+  | Partial<Image>
+  | Partial<Video>
+  | Partial<EncryptedImage>
+  | Partial<EncryptedVideo>;
 
 export const mediaValidator: TUnion<Media> = t.union([
   imageValidator,
diff --git a/lib/types/redux-types.js b/lib/types/redux-types.js
--- a/lib/types/redux-types.js
+++ b/lib/types/redux-types.js
@@ -121,7 +121,6 @@
 import type { ClientUpdatesResultWithUserInfos } from './update-types.js';
 import type { CurrentUserInfo, UserStore } from './user-types.js';
 import type { SetDeviceTokenActionPayload } from '../actions/device-actions.js';
-import type { Shape } from '../types/core.js';
 import type { NotifPermissionAlertInfo } from '../utils/push-alerts.js';
 
 export type BaseAppState<NavInfo: BaseNavInfo = BaseNavInfo> = {
@@ -804,7 +803,7 @@
     }
   | {
       +type: 'UPDATE_REPORTS_ENABLED',
-      +payload: Shape<EnabledReports>,
+      +payload: Partial<EnabledReports>,
     }
   | {
       +type: 'PROCESS_UPDATES',
@@ -1223,7 +1222,7 @@
     }
   | {
       +type: 'UPDATE_THEME_INFO',
-      +payload: Shape<GlobalThemeInfo>,
+      +payload: Partial<GlobalThemeInfo>,
     }
   | {
       +type: 'ADD_KEYSERVER',
diff --git a/lib/types/request-types.js b/lib/types/request-types.js
--- a/lib/types/request-types.js
+++ b/lib/types/request-types.js
@@ -4,7 +4,6 @@
 import t, { type TUnion, type TInterface } from 'tcomb';
 
 import { type ActivityUpdate } from './activity-types.js';
-import type { Shape } from './core.js';
 import type { SignedIdentityKeysBlob } from './crypto-types.js';
 import { signedIdentityKeysBlobValidator } from './crypto-types.js';
 import type { Platform, PlatformDetails } from './device-types.js';
@@ -96,13 +95,13 @@
   ...EntryInconsistencyReportShape,
 };
 
-type FailUnmentioned = Shape<{
+type FailUnmentioned = Partial<{
   +threadInfos: boolean,
   +entryInfos: boolean,
   +userInfos: boolean,
 }>;
 
-type StateChanges = Shape<{
+type StateChanges = Partial<{
   +rawThreadInfos: RawThreadInfo[],
   +rawEntryInfos: RawEntryInfo[],
   +currentUserInfo: CurrentUserInfo,
@@ -222,12 +221,12 @@
 export type ClientCheckStateServerRequest = {
   +type: 6,
   +hashesToCheck: { +[key: string]: number },
-  +failUnmentioned?: Shape<{
+  +failUnmentioned?: Partial<{
     +threadInfos: boolean,
     +entryInfos: boolean,
     +userInfos: boolean,
   }>,
-  +stateChanges?: Shape<{
+  +stateChanges?: Partial<{
     +rawThreadInfos: RawThreadInfo[],
     +rawEntryInfos: RawEntryInfo[],
     +currentUserInfo: CurrentUserInfo,
diff --git a/lib/types/session-types.js b/lib/types/session-types.js
--- a/lib/types/session-types.js
+++ b/lib/types/session-types.js
@@ -3,7 +3,6 @@
 import t, { type TInterface } from 'tcomb';
 
 import type { LogInActionSource } from './account-types.js';
-import type { Shape } from './core.js';
 import type { CalendarQuery } from './entry-types.js';
 import type { RawThreadInfos } from './thread-types.js';
 import {
@@ -93,7 +92,7 @@
   watchedIDs: $ReadOnlyArray<string>,
 };
 
-export type SessionIdentification = Shape<{
+export type SessionIdentification = Partial<{
   cookie: ?string,
   sessionID: ?string,
 }>;
diff --git a/lib/types/subscription-types.js b/lib/types/subscription-types.js
--- a/lib/types/subscription-types.js
+++ b/lib/types/subscription-types.js
@@ -3,7 +3,6 @@
 import _mapValues from 'lodash/fp/mapValues.js';
 import t, { type TInterface } from 'tcomb';
 
-import type { Shape } from './core.js';
 import { tShape } from '../utils/validation-utils.js';
 
 export const threadSubscriptions = Object.freeze({
@@ -21,7 +20,7 @@
 
 export type SubscriptionUpdateRequest = {
   threadID: string,
-  updatedFields: Shape<ThreadSubscription>,
+  updatedFields: Partial<ThreadSubscription>,
 };
 
 export type SubscriptionUpdateResponse = {
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
@@ -8,7 +8,6 @@
   clientAvatarValidator,
   type UpdateUserAvatarRequest,
 } from './avatar-types.js';
-import type { Shape } from './core.js';
 import type { CalendarQuery } from './entry-types.js';
 import type { Media } from './media-types.js';
 import type {
@@ -288,7 +287,7 @@
   },
 };
 
-export type ThreadChanges = Shape<{
+export type ThreadChanges = Partial<{
   +type: ThreadType,
   +name: string,
   +description: string,
diff --git a/lib/utils/call-server-endpoint.js b/lib/utils/call-server-endpoint.js
--- a/lib/utils/call-server-endpoint.js
+++ b/lib/utils/call-server-endpoint.js
@@ -13,7 +13,6 @@
 import { uploadBlob, type UploadBlob } from './upload-blob.js';
 import { updateLastCommunicatedPlatformDetailsActionType } from '../actions/device-actions.js';
 import { callServerEndpointTimeout } from '../shared/timeouts.js';
-import type { Shape } from '../types/core.js';
 import type { PlatformDetails } from '../types/device-types.js';
 import {
   type Endpoint,
@@ -30,7 +29,7 @@
 import type { ConnectionStatus } from '../types/socket-types';
 import type { CurrentUserInfo } from '../types/user-types.js';
 
-export type CallServerEndpointOptions = Shape<{
+export type CallServerEndpointOptions = Partial<{
   // null timeout means no timeout, which is the default for uploadBlob
   +timeout: ?number, // in milliseconds
   // getResultInfo will be called right before callServerEndpoint successfully
@@ -50,7 +49,7 @@
   +interface: CallServerEndpointResultInfoInterface,
 };
 
-export type CallServerEndpointResponse = Shape<{
+export type CallServerEndpointResponse = Partial<{
   +cookieChange: ServerSessionChange,
   +currentUserInfo: CurrentUserInfo,
   +error: string,
diff --git a/native/calendar/entry.react.js b/native/calendar/entry.react.js
--- a/native/calendar/entry.react.js
+++ b/native/calendar/entry.react.js
@@ -31,7 +31,6 @@
 import { colorIsDark } from 'lib/shared/color-utils.js';
 import { entryKey } from 'lib/shared/entry-utils.js';
 import { threadHasPermission } from 'lib/shared/thread-utils.js';
-import type { Shape } from 'lib/types/core.js';
 import type {
   CreateEntryInfo,
   SaveEntryInfo,
@@ -242,7 +241,7 @@
     };
   }
 
-  guardedSetState(input: Shape<State>) {
+  guardedSetState(input: Partial<State>) {
     if (this.mounted) {
       this.setState(input);
     }
diff --git a/native/components/node-height-measurer.react.js b/native/components/node-height-measurer.react.js
--- a/native/components/node-height-measurer.react.js
+++ b/native/components/node-height-measurer.react.js
@@ -5,8 +5,6 @@
 import { View, StyleSheet, PixelRatio } from 'react-native';
 import shallowequal from 'shallowequal';
 
-import type { Shape } from 'lib/types/core.js';
-
 import {
   addLifecycleListener,
   getCurrentLifecycleState,
@@ -133,7 +131,7 @@
   static getDerivedStateFromProps<InnerItem, InnerMergedItem>(
     props: Props<InnerItem, InnerMergedItem>,
     state: State<InnerItem, InnerMergedItem>,
-  ): ?Shape<State<InnerItem, InnerMergedItem>> {
+  ): ?Partial<State<InnerItem, InnerMergedItem>> {
     return NodeHeightMeasurer.getPossibleStateUpdateForNextBatch<
       InnerItem,
       InnerMergedItem,
@@ -143,7 +141,7 @@
   static getPossibleStateUpdateForNextBatch<InnerItem, InnerMergedItem>(
     props: Props<InnerItem, InnerMergedItem>,
     state: State<InnerItem, InnerMergedItem>,
-  ): ?Shape<State<InnerItem, InnerMergedItem>> {
+  ): ?Partial<State<InnerItem, InnerMergedItem>> {
     const { currentlyMeasuring, measuredHeights } = state;
 
     let stillMeasuring = false;
diff --git a/native/components/tag-input.react.js b/native/components/tag-input.react.js
--- a/native/components/tag-input.react.js
+++ b/native/components/tag-input.react.js
@@ -13,7 +13,6 @@
   Platform,
 } from 'react-native';
 
-import type { Shape } from 'lib/types/core.js';
 import type { ReactRefSetter } from 'lib/types/react-types.js';
 
 import TextInput from './text-input.react.js';
@@ -140,7 +139,7 @@
   static getDerivedStateFromProps(
     props: BaseTagInputProps<T>,
     state: State,
-  ): Shape<State> {
+  ): Partial<State> {
     const wrapperHeight = Math.max(
       Math.min(props.maxHeight, state.contentHeight),
       props.minHeight,
diff --git a/native/media/file-utils.js b/native/media/file-utils.js
--- a/native/media/file-utils.js
+++ b/native/media/file-utils.js
@@ -13,7 +13,6 @@
   fileInfoFromData,
   bytesNeededForFileTypeCheck,
 } from 'lib/media/file-utils.js';
-import type { Shape } from 'lib/types/core.js';
 import type {
   MediaMissionStep,
   MediaMissionFailure,
@@ -41,8 +40,8 @@
   +mime: ?string,
   +mediaType: ?MediaType,
 };
-type OptionalInputs = Shape<{ +mediaNativeID: ?string }>;
-type OptionalFields = Shape<{
+type OptionalInputs = Partial<{ +mediaNativeID: ?string }>;
+type OptionalFields = Partial<{
   +orientation: boolean,
   +mediaType: boolean,
   +mime: boolean,
diff --git a/native/redux/action-types.js b/native/redux/action-types.js
--- a/native/redux/action-types.js
+++ b/native/redux/action-types.js
@@ -3,7 +3,6 @@
 import type { Orientations } from 'react-native-orientation-locker';
 
 import { saveMessagesActionType } from 'lib/actions/message-actions.js';
-import type { Shape } from 'lib/types/core.js';
 import type { BaseAction } from 'lib/types/redux-types.js';
 
 import type { DimensionsInfo } from './dimensions-updater.react.js';
@@ -36,7 +35,7 @@
     }
   | {
       +type: 'UPDATE_DIMENSIONS',
-      +payload: Shape<DimensionsInfo>,
+      +payload: Partial<DimensionsInfo>,
     }
   | {
       +type: 'UPDATE_CONNECTIVITY',
@@ -44,7 +43,7 @@
     }
   | {
       +type: 'UPDATE_DEVICE_CAMERA_INFO',
-      +payload: Shape<DeviceCameraInfo>,
+      +payload: Partial<DeviceCameraInfo>,
     }
   | {
       +type: 'UPDATE_DEVICE_ORIENTATION',
diff --git a/native/utils/animation-utils.js b/native/utils/animation-utils.js
--- a/native/utils/animation-utils.js
+++ b/native/utils/animation-utils.js
@@ -9,8 +9,6 @@
   type TimingConfig,
 } from 'react-native-reanimated';
 
-import type { Shape } from 'lib/types/core.js';
-
 /* eslint-disable import/no-named-as-default-member */
 const {
   Clock,
@@ -87,7 +85,7 @@
   initialValue: Node | number,
   finalValue: Node | number,
   startStopClock: boolean = true,
-  config?: Shape<TimingConfig>,
+  config?: Partial<TimingConfig>,
 ): Node {
   const state = {
     finished: new Value(0),
@@ -117,7 +115,7 @@
 
 const defaultSpringConfig = SpringUtils.makeDefaultConfig();
 
-type SpringAnimationInitialState = Shape<{
+type SpringAnimationInitialState = Partial<{
   +velocity: Value | number,
 }>;
 function runSpring(
@@ -125,7 +123,7 @@
   initialValue: Node | number,
   finalValue: Node | number,
   startStopClock: boolean = true,
-  config?: Shape<SpringConfig>,
+  config?: Partial<SpringConfig>,
   initialState?: SpringAnimationInitialState,
 ): Node {
   const state = {
diff --git a/web/calendar/entry.react.js b/web/calendar/entry.react.js
--- a/web/calendar/entry.react.js
+++ b/web/calendar/entry.react.js
@@ -22,7 +22,6 @@
 import { colorIsDark } from 'lib/shared/color-utils.js';
 import { entryKey } from 'lib/shared/entry-utils.js';
 import { threadHasPermission } from 'lib/shared/thread-utils.js';
-import type { Shape } from 'lib/types/core.js';
 import {
   type EntryInfo,
   type CreateEntryInfo,
@@ -105,7 +104,7 @@
     this.nextSaveAttemptIndex = 0;
   }
 
-  guardedSetState(input: Shape<State>) {
+  guardedSetState(input: Partial<State>) {
     if (this.mounted) {
       this.setState(input);
     }
diff --git a/web/media/encrypted-multimedia.react.js b/web/media/encrypted-multimedia.react.js
--- a/web/media/encrypted-multimedia.react.js
+++ b/web/media/encrypted-multimedia.react.js
@@ -5,7 +5,6 @@
 import 'react-circular-progressbar/dist/styles.css';
 import { AlertCircle as AlertCircleIcon } from 'react-feather';
 
-import type { Shape } from 'lib/types/core.js';
 import type { EncryptedMediaType } from 'lib/types/media-types.js';
 
 import { decryptMedia } from './encryption-utils.js';
@@ -22,7 +21,7 @@
   +thumbnailEncryptionKey?: ?string,
   +placeholderSrc?: ?string,
   +multimediaClassName?: string,
-  +elementStyle?: ?Shape<CSSStyle>,
+  +elementStyle?: ?Partial<CSSStyle>,
   // if provided, this component will be shown instead of the loading indicator
   +loadingIndicatorComponent?: React.Node,
   // if true, the loading indicator will not be shown
diff --git a/web/media/loadable-video.react.js b/web/media/loadable-video.react.js
--- a/web/media/loadable-video.react.js
+++ b/web/media/loadable-video.react.js
@@ -3,8 +3,6 @@
 import invariant from 'invariant';
 import * as React from 'react';
 
-import type { Shape } from 'lib/types/core.js';
-
 import { decryptMedia } from './encryption-utils.js';
 import { preloadImage } from './media-utils.js';
 import type { CSSStyle } from '../types/styles';
@@ -21,7 +19,7 @@
   +uri: ?string,
   +thumbnailSource: ThumbnailSource,
   +thumbHashDataURL?: ?string,
-  +elementStyle?: ?Shape<CSSStyle>,
+  +elementStyle?: ?Partial<CSSStyle>,
   +multimediaClassName?: string,
 };
 
diff --git a/web/redux/redux-setup.js b/web/redux/redux-setup.js
--- a/web/redux/redux-setup.js
+++ b/web/redux/redux-setup.js
@@ -16,7 +16,6 @@
 import { isLoggedIn } from 'lib/selectors/user-selectors.js';
 import { invalidSessionDowngrade } from 'lib/shared/session-utils.js';
 import { canUseDatabaseOnWeb } from 'lib/shared/web-database.js';
-import type { Shape } from 'lib/types/core.js';
 import type { CryptoStore } from 'lib/types/crypto-types.js';
 import type { DraftStore } from 'lib/types/draft-types.js';
 import type { EnabledApps } from 'lib/types/enabled-apps.js';
@@ -99,7 +98,7 @@
 
 export type Action =
   | BaseAction
-  | { type: 'UPDATE_NAV_INFO', payload: Shape<NavInfo> }
+  | { type: 'UPDATE_NAV_INFO', payload: Partial<NavInfo> }
   | {
       type: 'UPDATE_WINDOW_DIMENSIONS',
       payload: WindowDimensions,