diff --git a/res/css/views/rooms/_EventTile.scss b/res/css/views/rooms/_EventTile.scss
index deb71fa678..ccf89adc42 100644
--- a/res/css/views/rooms/_EventTile.scss
+++ b/res/css/views/rooms/_EventTile.scss
@@ -56,7 +56,7 @@ $left-gutter: 64px;
     font-size: $font-14px;
     position: relative;
 
-    &[data-shape=thread_list][data-notification]::before {
+    &[data-shape=ThreadsList][data-notification]::before {
         content: "";
         position: absolute;
         width: 8px;
@@ -67,11 +67,11 @@ $left-gutter: 64px;
         left: auto;
     }
 
-    &[data-shape=thread_list][data-notification=total]::before {
+    &[data-shape=ThreadsList][data-notification=total]::before {
         background-color: $roomtile-default-badge-bg-color;
     }
 
-    &[data-shape=thread_list][data-notification=highlight]::before {
+    &[data-shape=ThreadsList][data-notification=highlight]::before {
         background-color: $alert;
     }
 
@@ -797,7 +797,7 @@ $left-gutter: 64px;
     white-space: nowrap;
 }
 
-.mx_EventTile[data-shape=thread_list] {
+.mx_EventTile[data-shape=ThreadsList] {
     --topOffset: 20px;
     --leftOffset: 46px;
 
diff --git a/src/components/structures/FilePanel.tsx b/src/components/structures/FilePanel.tsx
index 4062182266..6a7db3dc0b 100644
--- a/src/components/structures/FilePanel.tsx
+++ b/src/components/structures/FilePanel.tsx
@@ -33,7 +33,6 @@ import { replaceableComponent } from "../../utils/replaceableComponent";
 import ResizeNotifier from '../../utils/ResizeNotifier';
 import TimelinePanel from "./TimelinePanel";
 import Spinner from "../views/elements/Spinner";
-import { TileShape } from '../views/rooms/EventTile';
 import { Layout } from "../../settings/enums/Layout";
 import RoomContext, { TimelineRenderingType } from '../../contexts/RoomContext';
 
@@ -270,7 +269,6 @@ class FilePanel extends React.Component<IProps, IState> {
                             timelineSet={this.state.timelineSet}
                             showUrlPreview={false}
                             onPaginationRequest={this.onPaginationRequest}
-                            tileShape={TileShape.FileGrid}
                             resizeNotifier={this.props.resizeNotifier}
                             empty={emptyState}
                             layout={Layout.Group}
diff --git a/src/components/structures/MessagePanel.tsx b/src/components/structures/MessagePanel.tsx
index 689d02155f..938e01b8e7 100644
--- a/src/components/structures/MessagePanel.tsx
+++ b/src/components/structures/MessagePanel.tsx
@@ -29,7 +29,7 @@ import SettingsStore from '../../settings/SettingsStore';
 import RoomContext, { TimelineRenderingType } from "../../contexts/RoomContext";
 import { Layout } from "../../settings/enums/Layout";
 import { _t } from "../../languageHandler";
-import EventTile, { haveTileForEvent, IReadReceiptProps, TileShape } from "../views/rooms/EventTile";
+import EventTile, { haveTileForEvent, IReadReceiptProps } from "../views/rooms/EventTile";
 import { hasText } from "../../TextForEvent";
 import IRCTimelineProfileResizer from "../views/elements/IRCTimelineProfileResizer";
 import DMRoomMap from "../../utils/DMRoomMap";
@@ -144,9 +144,6 @@ interface IProps {
     // className for the panel
     className: string;
 
-    // shape parameter to be passed to EventTiles
-    tileShape?: TileShape;
-
     // show twelve hour timestamps
     isTwelveHour?: boolean;
 
@@ -802,7 +799,6 @@ export default class MessagePanel extends React.Component<IProps, IState> {
                     showUrlPreview={this.props.showUrlPreview}
                     checkUnmounting={this.isUnmounting}
                     eventSendStatus={mxEv.getAssociatedStatus()}
-                    tileShape={this.props.tileShape}
                     isTwelveHour={this.props.isTwelveHour}
                     permalinkCreator={this.props.permalinkCreator}
                     last={last}
@@ -994,7 +990,10 @@ export default class MessagePanel extends React.Component<IProps, IState> {
         const style = this.props.hidden ? { display: 'none' } : {};
 
         let whoIsTyping;
-        if (this.props.room && !this.props.tileShape && this.state.showTypingNotifications) {
+        if (this.props.room &&
+            this.state.showTypingNotifications &&
+            this.context.timelineRenderingType === TimelineRenderingType.Room
+        ) {
             whoIsTyping = (<WhoIsTypingTile
                 room={this.props.room}
                 onShown={this.onTypingShown}
diff --git a/src/components/structures/NotificationPanel.tsx b/src/components/structures/NotificationPanel.tsx
index f28804db38..d7eddb4ebb 100644
--- a/src/components/structures/NotificationPanel.tsx
+++ b/src/components/structures/NotificationPanel.tsx
@@ -23,7 +23,6 @@ import BaseCard from "../views/right_panel/BaseCard";
 import { replaceableComponent } from "../../utils/replaceableComponent";
 import TimelinePanel from "./TimelinePanel";
 import Spinner from "../views/elements/Spinner";
-import { TileShape } from "../views/rooms/EventTile";
 import { Layout } from "../../settings/enums/Layout";
 import RoomContext, { TimelineRenderingType } from "../../contexts/RoomContext";
 
@@ -53,7 +52,6 @@ export default class NotificationPanel extends React.PureComponent<IProps> {
                     manageReadMarkers={false}
                     timelineSet={timelineSet}
                     showUrlPreview={false}
-                    tileShape={TileShape.Notif}
                     empty={emptyState}
                     alwaysShowTimestamps={true}
                     layout={Layout.Group}
diff --git a/src/components/structures/ThreadPanel.tsx b/src/components/structures/ThreadPanel.tsx
index 1148ee4402..151af8377a 100644
--- a/src/components/structures/ThreadPanel.tsx
+++ b/src/components/structures/ThreadPanel.tsx
@@ -36,7 +36,6 @@ import ContextMenu, { ChevronFace, MenuItemRadio, useContextMenu } from './Conte
 import RoomContext, { TimelineRenderingType } from '../../contexts/RoomContext';
 import TimelinePanel from './TimelinePanel';
 import { Layout } from '../../settings/enums/Layout';
-import { TileShape } from '../views/rooms/EventTile';
 import { RoomPermalinkCreator } from '../../utils/permalinks/Permalinks';
 import { useEventEmitter } from '../../hooks/useEventEmitter';
 
@@ -302,7 +301,6 @@ const ThreadPanel: React.FC<IProps> = ({ roomId, onClose, permalinkCreator }) =>
                         className="mx_RoomView_messagePanel mx_GroupLayout"
                         membersLoaded={true}
                         permalinkCreator={permalinkCreator}
-                        tileShape={TileShape.ThreadPanel}
                         disableGrouping={true}
                     />
                 ) }
diff --git a/src/components/structures/ThreadView.tsx b/src/components/structures/ThreadView.tsx
index da8d49aaeb..c26c64428c 100644
--- a/src/components/structures/ThreadView.tsx
+++ b/src/components/structures/ThreadView.tsx
@@ -28,7 +28,6 @@ import BaseCard from "../views/right_panel/BaseCard";
 import { RightPanelPhases } from "../../stores/right-panel/RightPanelStorePhases";
 import { replaceableComponent } from "../../utils/replaceableComponent";
 import ResizeNotifier from '../../utils/ResizeNotifier';
-import { TileShape } from '../views/rooms/EventTile';
 import MessageComposer from '../views/rooms/MessageComposer';
 import { RoomPermalinkCreator } from '../../utils/permalinks/Permalinks';
 import { Layout } from '../../settings/enums/Layout';
@@ -284,7 +283,6 @@ export default class ThreadView extends React.Component<IProps, IState> {
                             sendReadReceiptOnLoad={true}
                             timelineSet={this.state?.thread?.timelineSet}
                             showUrlPreview={true}
-                            tileShape={TileShape.Thread}
                             // ThreadView doesn't support IRC layout at this time
                             layout={this.state.layout === Layout.Bubble ? Layout.Bubble : Layout.Group}
                             hideThreadedMessages={false}
diff --git a/src/components/structures/TimelinePanel.tsx b/src/components/structures/TimelinePanel.tsx
index a5cb4add5a..32ed88103e 100644
--- a/src/components/structures/TimelinePanel.tsx
+++ b/src/components/structures/TimelinePanel.tsx
@@ -39,7 +39,7 @@ import { Action } from '../../dispatcher/actions';
 import { Key } from '../../Keyboard';
 import Timer from '../../utils/Timer';
 import shouldHideEvent from '../../shouldHideEvent';
-import { haveTileForEvent, TileShape } from "../views/rooms/EventTile";
+import { haveTileForEvent } from "../views/rooms/EventTile";
 import { UIFeature } from "../../settings/UIFeature";
 import { replaceableComponent } from "../../utils/replaceableComponent";
 import { arrayFastClone } from "../../utils/arrays";
@@ -103,9 +103,6 @@ interface IProps {
     // classname to use for the messagepanel
     className?: string;
 
-    // shape property to be passed to EventTiles
-    tileShape?: TileShape;
-
     // placeholder to use if the timeline is empty
     empty?: ReactNode;
 
@@ -1644,7 +1641,6 @@ class TimelinePanel extends React.Component<IProps, IState> {
                     this.state.alwaysShowTimestamps
                 }
                 className={this.props.className}
-                tileShape={this.props.tileShape}
                 resizeNotifier={this.props.resizeNotifier}
                 getRelationsForEvent={this.getRelationsForEvent}
                 editState={this.props.editState}
diff --git a/src/components/views/audio_messages/AudioPlayerBase.tsx b/src/components/views/audio_messages/AudioPlayerBase.tsx
index f645c53387..321fdd6ecf 100644
--- a/src/components/views/audio_messages/AudioPlayerBase.tsx
+++ b/src/components/views/audio_messages/AudioPlayerBase.tsx
@@ -18,7 +18,6 @@ import React, { ReactNode } from "react";
 import { logger } from "matrix-js-sdk/src/logger";
 
 import { Playback, PlaybackState } from "../../../audio/Playback";
-import { TileShape } from "../rooms/EventTile";
 import { UPDATE_EVENT } from "../../../stores/AsyncStore";
 import { replaceableComponent } from "../../../utils/replaceableComponent";
 import { _t } from "../../../languageHandler";
@@ -29,7 +28,6 @@ interface IProps {
     playback: Playback;
 
     mediaName?: string;
-    tileShape?: TileShape;
 }
 
 interface IState {
diff --git a/src/components/views/audio_messages/RecordingPlayback.tsx b/src/components/views/audio_messages/RecordingPlayback.tsx
index 04c61affd9..a80751fd61 100644
--- a/src/components/views/audio_messages/RecordingPlayback.tsx
+++ b/src/components/views/audio_messages/RecordingPlayback.tsx
@@ -19,16 +19,19 @@ import React, { ReactNode } from "react";
 import PlayPauseButton from "./PlayPauseButton";
 import PlaybackClock from "./PlaybackClock";
 import { replaceableComponent } from "../../../utils/replaceableComponent";
-import { TileShape } from "../rooms/EventTile";
 import PlaybackWaveform from "./PlaybackWaveform";
 import AudioPlayerBase from "./AudioPlayerBase";
+import RoomContext, { TimelineRenderingType } from "../../../contexts/RoomContext";
 
 @replaceableComponent("views.audio_messages.RecordingPlayback")
 export default class RecordingPlayback extends AudioPlayerBase {
+    static contextType = RoomContext;
+    public context!: React.ContextType<typeof RoomContext>;
+
     private get isWaveformable(): boolean {
-        return this.props.tileShape !== TileShape.Notif
-            && this.props.tileShape !== TileShape.FileGrid
-            && this.props.tileShape !== TileShape.Pinned;
+        return this.context.timelineRenderingType !== TimelineRenderingType.Notification
+            && this.context.timelineRenderingType !== TimelineRenderingType.File
+            && this.context.timelineRenderingType !== TimelineRenderingType.Pinned;
     }
 
     protected renderComponent(): ReactNode {
diff --git a/src/components/views/messages/IBodyProps.ts b/src/components/views/messages/IBodyProps.ts
index c39dfa4798..76c823b185 100644
--- a/src/components/views/messages/IBodyProps.ts
+++ b/src/components/views/messages/IBodyProps.ts
@@ -17,7 +17,6 @@ limitations under the License.
 import { MatrixEvent } from "matrix-js-sdk/src/models/event";
 import { Relations } from "matrix-js-sdk/src/models/relations";
 
-import { TileShape } from "../rooms/EventTile";
 import { MediaEventHelper } from "../../../utils/MediaEventHelper";
 import EditorStateTransfer from "../../../utils/EditorStateTransfer";
 import { RoomPermalinkCreator } from "../../../utils/permalinks/Permalinks";
@@ -36,7 +35,6 @@ export interface IBodyProps {
 
     showUrlPreview?: boolean;
     forExport?: boolean;
-    tileShape: TileShape;
     maxImageHeight?: number;
     replacingEventId?: string;
     editState?: EditorStateTransfer;
diff --git a/src/components/views/messages/MAudioBody.tsx b/src/components/views/messages/MAudioBody.tsx
index d3bc2fb107..4af3821596 100644
--- a/src/components/views/messages/MAudioBody.tsx
+++ b/src/components/views/messages/MAudioBody.tsx
@@ -28,6 +28,7 @@ import { IBodyProps } from "./IBodyProps";
 import { PlaybackManager } from "../../../audio/PlaybackManager";
 import { isVoiceMessage } from "../../../utils/EventUtils";
 import { PlaybackQueue } from "../../../audio/PlaybackQueue";
+import RoomContext, { TimelineRenderingType } from "../../../contexts/RoomContext";
 
 interface IState {
     error?: Error;
@@ -36,6 +37,9 @@ interface IState {
 
 @replaceableComponent("views.messages.MAudioBody")
 export default class MAudioBody extends React.PureComponent<IBodyProps, IState> {
+    static contextType = RoomContext;
+    public context!: React.ContextType<typeof RoomContext>;
+
     constructor(props: IBodyProps) {
         super(props);
 
@@ -82,6 +86,12 @@ export default class MAudioBody extends React.PureComponent<IBodyProps, IState>
         this.state.playback?.destroy();
     }
 
+    protected get showFileBody(): boolean {
+        return this.context.timelineRenderingType !== TimelineRenderingType.Room &&
+            this.context.timelineRenderingType !== TimelineRenderingType.Pinned &&
+            this.context.timelineRenderingType !== TimelineRenderingType.Search;
+    }
+
     public render() {
         if (this.state.error) {
             return (
@@ -115,7 +125,7 @@ export default class MAudioBody extends React.PureComponent<IBodyProps, IState>
         return (
             <span className="mx_MAudioBody">
                 <AudioPlayer playback={this.state.playback} mediaName={this.props.mxEvent.getContent().body} />
-                { this.props.tileShape && <MFileBody {...this.props} showGenericPlaceholder={false} /> }
+                { this.showFileBody && <MFileBody {...this.props} showGenericPlaceholder={false} /> }
             </span>
         );
     }
diff --git a/src/components/views/messages/MFileBody.tsx b/src/components/views/messages/MFileBody.tsx
index 3df84b5101..ce99ddc688 100644
--- a/src/components/views/messages/MFileBody.tsx
+++ b/src/components/views/messages/MFileBody.tsx
@@ -24,12 +24,12 @@ import AccessibleButton from "../elements/AccessibleButton";
 import { replaceableComponent } from "../../../utils/replaceableComponent";
 import { mediaFromContent } from "../../../customisations/Media";
 import ErrorDialog from "../dialogs/ErrorDialog";
-import { TileShape } from "../rooms/EventTile";
 import { presentableTextForFile } from "../../../utils/FileUtils";
 import { IMediaEventContent } from "../../../customisations/models/IMediaEventContent";
 import { IBodyProps } from "./IBodyProps";
 import { FileDownloader } from "../../../utils/FileDownloader";
 import TextWithTooltip from "../elements/TextWithTooltip";
+import RoomContext, { TimelineRenderingType } from "../../../contexts/RoomContext";
 
 export let DOWNLOAD_ICON_URL; // cached copy of the download.svg asset for the sandboxed iframe later on
 
@@ -108,6 +108,9 @@ interface IState {
 
 @replaceableComponent("views.messages.MFileBody")
 export default class MFileBody extends React.Component<IProps, IState> {
+    static contextType = RoomContext;
+    public context!: React.ContextType<typeof RoomContext>;
+
     static defaultProps = {
         showGenericPlaceholder: true,
     };
@@ -223,8 +226,15 @@ export default class MFileBody extends React.Component<IProps, IState> {
             </span>;
         }
 
-        const showDownloadLink = (this.props.tileShape || !this.props.showGenericPlaceholder) &&
-            this.props.tileShape !== TileShape.Thread;
+        let showDownloadLink = !this.props.showGenericPlaceholder || (
+            this.context.timelineRenderingType !== TimelineRenderingType.Room &&
+            this.context.timelineRenderingType !== TimelineRenderingType.Search &&
+            this.context.timelineRenderingType !== TimelineRenderingType.Pinned
+        );
+
+        if (this.context.timelineRenderingType === TimelineRenderingType.Thread) {
+            showDownloadLink = false;
+        }
 
         if (isEncrypted) {
             if (!this.state.decryptedBlob) {
@@ -334,9 +344,11 @@ export default class MFileBody extends React.Component<IProps, IState> {
                             <span className="mx_MFileBody_download_icon" />
                             { _t("Download %(text)s", { text: this.linkText }) }
                         </a>
-                        { this.props.tileShape === TileShape.FileGrid && <div className="mx_MImageBody_size">
-                            { this.content.info && this.content.info.size ? filesize(this.content.info.size) : "" }
-                        </div> }
+                        { this.context.timelineRenderingType === TimelineRenderingType.File && (
+                            <div className="mx_MImageBody_size">
+                                { this.content.info && this.content.info.size ? filesize(this.content.info.size) : "" }
+                            </div>
+                        ) }
                     </div> }
                 </span>
             );
diff --git a/src/components/views/messages/MImageBody.tsx b/src/components/views/messages/MImageBody.tsx
index 809b44d06b..1b0aa1444d 100644
--- a/src/components/views/messages/MImageBody.tsx
+++ b/src/components/views/messages/MImageBody.tsx
@@ -26,7 +26,6 @@ import MFileBody from './MFileBody';
 import Modal from '../../../Modal';
 import { _t } from '../../../languageHandler';
 import SettingsStore from "../../../settings/SettingsStore";
-import MatrixClientContext from "../../../contexts/MatrixClientContext";
 import InlineSpinner from '../elements/InlineSpinner';
 import { replaceableComponent } from "../../../utils/replaceableComponent";
 import { Media, mediaFromContent } from "../../../customisations/Media";
@@ -34,8 +33,9 @@ import { BLURHASH_FIELD } from "../../../ContentMessages";
 import { IMediaEventContent } from '../../../customisations/models/IMediaEventContent';
 import ImageView from '../elements/ImageView';
 import { IBodyProps } from "./IBodyProps";
-import { TileShape } from '../rooms/EventTile';
 import { ImageSize, suggestedSize as suggestedImageSize } from "../../../settings/enums/ImageSize";
+import { MatrixClientPeg } from '../../../MatrixClientPeg';
+import RoomContext, { TimelineRenderingType } from "../../../contexts/RoomContext";
 
 interface IState {
     decryptedUrl?: string;
@@ -55,7 +55,9 @@ interface IState {
 
 @replaceableComponent("views.messages.MImageBody")
 export default class MImageBody extends React.Component<IBodyProps, IState> {
-    static contextType = MatrixClientContext;
+    static contextType = RoomContext;
+    public context!: React.ContextType<typeof RoomContext>;
+
     private unmounted = true;
     private image = createRef<HTMLImageElement>();
     private timeout?: number;
@@ -297,7 +299,7 @@ export default class MImageBody extends React.Component<IBodyProps, IState> {
 
     componentDidMount() {
         this.unmounted = false;
-        this.context.on('sync', this.onClientSync);
+        MatrixClientPeg.get().on('sync', this.onClientSync);
 
         const showImage = this.state.showImage ||
             localStorage.getItem("mx_ShowImage_" + this.props.mxEvent.getId()) === "true";
@@ -327,7 +329,7 @@ export default class MImageBody extends React.Component<IBodyProps, IState> {
 
     componentWillUnmount() {
         this.unmounted = true;
-        this.context.removeListener('sync', this.onClientSync);
+        MatrixClientPeg.get().removeListener('sync', this.onClientSync);
         this.clearBlurhashTimeout();
         SettingsStore.unwatchSetting(this.sizeWatcher);
     }
@@ -524,9 +526,11 @@ export default class MImageBody extends React.Component<IBodyProps, IState> {
          * In the room timeline or the thread context we don't need the download
          * link as the message action bar will fullfil that
          */
-        const hasMessageActionBar = !this.props.tileShape
-            || this.props.tileShape === TileShape.Thread
-            || this.props.tileShape === TileShape.ThreadPanel;
+        const hasMessageActionBar = this.context.timelineRenderingType === TimelineRenderingType.Room
+            || this.context.timelineRenderingType === TimelineRenderingType.Pinned
+            || this.context.timelineRenderingType === TimelineRenderingType.Search
+            || this.context.timelineRenderingType === TimelineRenderingType.Thread
+            || this.context.timelineRenderingType === TimelineRenderingType.ThreadsList;
         if (!hasMessageActionBar) {
             return <MFileBody {...this.props} showGenericPlaceholder={false} />;
         }
diff --git a/src/components/views/messages/MVideoBody.tsx b/src/components/views/messages/MVideoBody.tsx
index 202829a619..22d5399d90 100644
--- a/src/components/views/messages/MVideoBody.tsx
+++ b/src/components/views/messages/MVideoBody.tsx
@@ -28,6 +28,7 @@ import { IMediaEventContent } from "../../../customisations/models/IMediaEventCo
 import { IBodyProps } from "./IBodyProps";
 import MFileBody from "./MFileBody";
 import { ImageSize, suggestedSize as suggestedVideoSize } from "../../../settings/enums/ImageSize";
+import RoomContext, { TimelineRenderingType } from "../../../contexts/RoomContext";
 
 interface IState {
     decryptedUrl?: string;
@@ -41,6 +42,9 @@ interface IState {
 
 @replaceableComponent("views.messages.MVideoBody")
 export default class MVideoBody extends React.PureComponent<IBodyProps, IState> {
+    static contextType = RoomContext;
+    public context!: React.ContextType<typeof RoomContext>;
+
     private videoRef = React.createRef<HTMLVideoElement>();
     private sizeWatcher: string;
 
@@ -235,9 +239,15 @@ export default class MVideoBody extends React.PureComponent<IBodyProps, IState>
         this.props.onHeightChanged();
     };
 
+    protected get showFileBody(): boolean {
+        return this.context.timelineRenderingType !== TimelineRenderingType.Room &&
+            this.context.timelineRenderingType !== TimelineRenderingType.Pinned &&
+            this.context.timelineRenderingType !== TimelineRenderingType.Search;
+    }
+
     private getFileBody = () => {
         if (this.props.forExport) return null;
-        return this.props.tileShape && <MFileBody {...this.props} showGenericPlaceholder={false} />;
+        return this.showFileBody && <MFileBody {...this.props} showGenericPlaceholder={false} />;
     };
 
     render() {
diff --git a/src/components/views/messages/MVoiceMessageBody.tsx b/src/components/views/messages/MVoiceMessageBody.tsx
index 5a8a633855..bc42ff5551 100644
--- a/src/components/views/messages/MVoiceMessageBody.tsx
+++ b/src/components/views/messages/MVoiceMessageBody.tsx
@@ -47,8 +47,8 @@ export default class MVoiceMessageBody extends MAudioBody {
         // At this point we should have a playable state
         return (
             <span className="mx_MVoiceMessageBody">
-                <RecordingPlayback playback={this.state.playback} tileShape={this.props.tileShape} />
-                { this.props.tileShape && <MFileBody {...this.props} showGenericPlaceholder={false} /> }
+                <RecordingPlayback playback={this.state.playback} />
+                { this.showFileBody && <MFileBody {...this.props} showGenericPlaceholder={false} /> }
             </span>
         );
     }
diff --git a/src/components/views/messages/MessageEvent.tsx b/src/components/views/messages/MessageEvent.tsx
index ec310fef0c..578b887420 100644
--- a/src/components/views/messages/MessageEvent.tsx
+++ b/src/components/views/messages/MessageEvent.tsx
@@ -161,7 +161,6 @@ export default class MessageEvent extends React.Component<IProps> implements IMe
             highlights={this.props.highlights}
             highlightLink={this.props.highlightLink}
             showUrlPreview={this.props.showUrlPreview}
-            tileShape={this.props.tileShape}
             forExport={this.props.forExport}
             maxImageHeight={this.props.maxImageHeight}
             replacingEventId={this.props.replacingEventId}
diff --git a/src/components/views/messages/SenderProfile.tsx b/src/components/views/messages/SenderProfile.tsx
index d363bdef94..7f30c81793 100644
--- a/src/components/views/messages/SenderProfile.tsx
+++ b/src/components/views/messages/SenderProfile.tsx
@@ -24,7 +24,7 @@ import { getUserNameColorClass } from '../../../utils/FormattingUtils';
 import MatrixClientContext from "../../../contexts/MatrixClientContext";
 import { replaceableComponent } from "../../../utils/replaceableComponent";
 import UserIdentifier from '../../../customisations/UserIdentifier';
-import { TileShape } from '../rooms/EventTile';
+import RoomContext, { TimelineRenderingType } from '../../../contexts/RoomContext';
 import SettingsStore from "../../../settings/SettingsStore";
 import { MatrixClientPeg } from "../../../MatrixClientPeg";
 
@@ -32,7 +32,6 @@ interface IProps {
     mxEvent: MatrixEvent;
     onClick?(): void;
     enableFlair: boolean;
-    tileShape?: TileShape;
 }
 
 interface IState {
@@ -121,41 +120,44 @@ export default class SenderProfile extends React.Component<IProps, IState> {
         const displayName = member?.rawDisplayName || mxEvent.getSender() || "";
         const mxid = member?.userId || mxEvent.getSender() || "";
 
-        if (msgtype === MsgType.Emote && this.props.tileShape !== TileShape.ThreadPanel) {
-            return null; // emote message must include the name so don't duplicate it
-        }
+        return <RoomContext.Consumer>
+            { roomContext => {
+                if (msgtype === MsgType.Emote &&
+                    roomContext.timelineRenderingType !== TimelineRenderingType.ThreadsList
+                ) {
+                    return null; // emote message must include the name so don't duplicate it
+                }
 
-        let mxidElement;
-        if (disambiguate) {
-            mxidElement = (
-                <span className="mx_SenderProfile_mxid">
-                    { UserIdentifier.getDisplayUserIdentifier(
-                        mxid, { withDisplayName: true, roomId: mxEvent.getRoomId() },
-                    ) }
-                </span>
-            );
-        }
+                let mxidElement;
+                if (disambiguate) {
+                    mxidElement = (
+                        <span className="mx_SenderProfile_mxid">
+                            { UserIdentifier.getDisplayUserIdentifier(
+                                mxid, { withDisplayName: true, roomId: mxEvent.getRoomId() },
+                            ) }
+                        </span>
+                    );
+                }
 
-        let flair;
-        if (this.props.enableFlair) {
-            const displayedGroups = this.getDisplayedGroups(
-                this.state.userGroups, this.state.relatedGroups,
-            );
+                let flair;
+                if (this.props.enableFlair) {
+                    const displayedGroups = this.getDisplayedGroups(
+                        this.state.userGroups, this.state.relatedGroups,
+                    );
 
-            flair = <Flair key='flair'
-                userId={mxEvent.getSender()}
-                groups={displayedGroups}
-            />;
-        }
+                    flair = <Flair key='flair' userId={mxEvent.getSender()} groups={displayedGroups} />;
+                }
 
-        return (
-            <div className="mx_SenderProfile" dir="auto" onClick={this.props.onClick}>
-                <span className={`mx_SenderProfile_displayName ${colorClass}`}>
-                    { displayName }
-                </span>
-                { mxidElement }
-                { flair }
-            </div>
-        );
+                return (
+                    <div className="mx_SenderProfile" dir="auto" onClick={this.props.onClick}>
+                        <span className={`mx_SenderProfile_displayName ${colorClass}`}>
+                            { displayName }
+                        </span>
+                        { mxidElement }
+                        { flair }
+                    </div>
+                );
+            } }
+        </RoomContext.Consumer>;
     }
 }
diff --git a/src/components/views/right_panel/PinnedMessagesCard.tsx b/src/components/views/right_panel/PinnedMessagesCard.tsx
index 44c6b2c922..c5ba91c275 100644
--- a/src/components/views/right_panel/PinnedMessagesCard.tsx
+++ b/src/components/views/right_panel/PinnedMessagesCard.tsx
@@ -29,6 +29,7 @@ import PinningUtils from "../../../utils/PinningUtils";
 import { useAsyncMemo } from "../../../hooks/useAsyncMemo";
 import PinnedEventTile from "../rooms/PinnedEventTile";
 import { useRoomState } from "../../../hooks/useRoomState";
+import RoomContext, { TimelineRenderingType } from "../../../contexts/RoomContext";
 
 interface IProps {
     room: Room;
@@ -78,6 +79,7 @@ export const useReadPinnedEvents = (room: Room): Set<string> => {
 
 const PinnedMessagesCard = ({ room, onClose }: IProps) => {
     const cli = useContext(MatrixClientContext);
+    const roomContext = useContext(RoomContext);
     const canUnpin = useRoomState(room, state => state.mayClientSendStateEvent(EventType.RoomPinnedEvents, cli));
     const pinnedEventIds = usePinnedEvents(room);
     const readPinnedEvents = useReadPinnedEvents(room);
@@ -166,7 +168,12 @@ const PinnedMessagesCard = ({ room, onClose }: IProps) => {
         className="mx_PinnedMessagesCard"
         onClose={onClose}
     >
-        { content }
+        <RoomContext.Provider value={{
+            ...roomContext,
+            timelineRenderingType: TimelineRenderingType.Pinned,
+        }}>
+            { content }
+        </RoomContext.Provider>
     </BaseCard>;
 };
 
diff --git a/src/components/views/rooms/EventTile.tsx b/src/components/views/rooms/EventTile.tsx
index 2b95c946bd..13218d1297 100644
--- a/src/components/views/rooms/EventTile.tsx
+++ b/src/components/views/rooms/EventTile.tsx
@@ -64,7 +64,7 @@ import SettingsStore from "../../../settings/SettingsStore";
 import MKeyVerificationConclusion from "../messages/MKeyVerificationConclusion";
 import { showThread } from '../../../dispatcher/dispatch-actions/threads';
 import { MessagePreviewStore } from '../../../stores/room-list/MessagePreviewStore';
-import { TimelineRenderingType } from "../../../contexts/RoomContext";
+import RoomContext, { TimelineRenderingType } from "../../../contexts/RoomContext";
 import { MediaEventHelper } from "../../../utils/MediaEventHelper";
 import Toolbar from '../../../accessibility/Toolbar';
 import { RovingAccessibleTooltipButton } from '../../../accessibility/roving/RovingAccessibleTooltipButton';
@@ -213,14 +213,6 @@ export interface IReadReceiptProps {
     ts: number;
 }
 
-export enum TileShape {
-    Notif = "notif",
-    FileGrid = "file_grid",
-    Pinned = "pinned",
-    Thread = "thread",
-    ThreadPanel = "thread_list"
-}
-
 interface IProps {
     // the MatrixEvent to show
     mxEvent: MatrixEvent;
@@ -281,14 +273,6 @@ interface IProps {
     // that we can tell when it changes.
     eventSendStatus?: string;
 
-    // the shape of the tile. by default, the layout is intended for the
-    // normal room timeline.  alternative values are: "file_list", "file_grid"
-    // and "notif".  This could be done by CSS, but it'd be horribly inefficient.
-    // It could also be done by subclassing EventTile, but that'd be quite
-    // boiilerplatey.  So just make the necessary render decisions conditional
-    // for now.
-    tileShape?: TileShape;
-
     forExport?: boolean;
 
     // show twelve hour timestamps
@@ -367,6 +351,7 @@ interface IState {
     threadNotification?: NotificationCountType;
 }
 
+// MUST be rendered within a RoomContext with a set timelineRenderingType
 @replaceableComponent("views.rooms.EventTile")
 export default class EventTile extends React.Component<IProps, IState> {
     private suppressReadReceiptAnimation: boolean;
@@ -385,13 +370,12 @@ export default class EventTile extends React.Component<IProps, IState> {
         layout: Layout.Group,
     };
 
-    static contextType = MatrixClientContext;
-    public context!: React.ContextType<typeof MatrixClientContext>;
+    static contextType = RoomContext;
+    public context!: React.ContextType<typeof RoomContext>;
 
     constructor(props: IProps, context: React.ContextType<typeof MatrixClientContext>) {
         super(props, context);
 
-        this.context = context;
         const thread = this.thread;
 
         this.state = {
@@ -437,12 +421,12 @@ export default class EventTile extends React.Component<IProps, IState> {
         if (!this.props.mxEvent) return false;
 
         // Sanity check (should never happen, but we shouldn't explode if it does)
-        const room = this.context.getRoom(this.props.mxEvent.getRoomId());
+        const room = MatrixClientPeg.get().getRoom(this.props.mxEvent.getRoomId());
         if (!room) return false;
 
         // Quickly check to see if the event was sent by us. If it wasn't, it won't qualify for
         // special read receipts.
-        const myUserId = this.context.getUserId();
+        const myUserId = MatrixClientPeg.get().getUserId();
         if (this.props.mxEvent.getSender() !== myUserId) return false;
 
         // Finally, determine if the type is relevant to the user. This notably excludes state
@@ -473,7 +457,7 @@ export default class EventTile extends React.Component<IProps, IState> {
 
         // If anyone has read the event besides us, we don't want to show a sent receipt.
         const receipts = this.props.readReceipts || [];
-        const myUserId = this.context.getUserId();
+        const myUserId = MatrixClientPeg.get().getUserId();
         if (receipts.some(r => r.userId !== myUserId)) return false;
 
         // Finally, we should show a receipt.
@@ -501,7 +485,7 @@ export default class EventTile extends React.Component<IProps, IState> {
 
     componentDidMount() {
         this.suppressReadReceiptAnimation = false;
-        const client = this.context;
+        const client = MatrixClientPeg.get();
         if (!this.props.forExport) {
             client.on("deviceVerificationChanged", this.onDeviceVerificationChanged);
             client.on("userTrustStatusChanged", this.onUserVerificationChanged);
@@ -526,12 +510,12 @@ export default class EventTile extends React.Component<IProps, IState> {
             }
         }
 
-        const room = this.context.getRoom(this.props.mxEvent.getRoomId());
+        const room = MatrixClientPeg.get().getRoom(this.props.mxEvent.getRoomId());
         room?.on(ThreadEvent.New, this.onNewThread);
     }
 
     private setupNotificationListener = (thread: Thread): void => {
-        const room = this.context.getRoom(this.props.mxEvent.getRoomId());
+        const room = MatrixClientPeg.get().getRoom(this.props.mxEvent.getRoomId());
         const notifications = RoomNotificationStateStore.instance.getThreadsRoomState(room);
 
         this.threadState = notifications.getThreadRoomState(thread);
@@ -592,7 +576,7 @@ export default class EventTile extends React.Component<IProps, IState> {
     }
 
     componentWillUnmount() {
-        const client = this.context;
+        const client = MatrixClientPeg.get();
         client.removeListener("deviceVerificationChanged", this.onDeviceVerificationChanged);
         client.removeListener("userTrustStatusChanged", this.onUserVerificationChanged);
         client.removeListener("Room.receipt", this.onRoomReceipt);
@@ -606,7 +590,7 @@ export default class EventTile extends React.Component<IProps, IState> {
             this.props.mxEvent.off(ThreadEvent.Update, this.updateThread);
         }
 
-        const room = this.context.getRoom(this.props.mxEvent.getRoomId());
+        const room = MatrixClientPeg.get().getRoom(this.props.mxEvent.getRoomId());
         room?.off(ThreadEvent.New, this.onNewThread);
         if (this.threadState) {
             this.threadState.off(NotificationStateEvents.Update, this.onThreadStateUpdate);
@@ -616,7 +600,7 @@ export default class EventTile extends React.Component<IProps, IState> {
     componentDidUpdate(prevProps: IProps, prevState: IState, snapshot) {
         // If we're not listening for receipts and expect to be, register a listener.
         if (!this.isListeningForReceipts && (this.shouldShowSentReceipt || this.shouldShowSendingReceipt)) {
-            this.context.on("Room.receipt", this.onRoomReceipt);
+            MatrixClientPeg.get().on("Room.receipt", this.onRoomReceipt);
             this.isListeningForReceipts = true;
         }
     }
@@ -624,7 +608,7 @@ export default class EventTile extends React.Component<IProps, IState> {
     private onNewThread = (thread: Thread) => {
         if (thread.id === this.props.mxEvent.getId()) {
             this.updateThread(thread);
-            const room = this.context.getRoom(this.props.mxEvent.getRoomId());
+            const room = MatrixClientPeg.get().getRoom(this.props.mxEvent.getRoomId());
             room.off(ThreadEvent.New, this.onNewThread);
         }
     };
@@ -734,7 +718,7 @@ export default class EventTile extends React.Component<IProps, IState> {
 
     private onRoomReceipt = (ev: MatrixEvent, room: Room): void => {
         // ignore events for other rooms
-        const tileRoom = this.context.getRoom(this.props.mxEvent.getRoomId());
+        const tileRoom = MatrixClientPeg.get().getRoom(this.props.mxEvent.getRoomId());
         if (room !== tileRoom) return;
 
         if (!this.shouldShowSentReceipt && !this.shouldShowSendingReceipt && !this.isListeningForReceipts) {
@@ -746,7 +730,7 @@ export default class EventTile extends React.Component<IProps, IState> {
         this.forceUpdate(() => {
             // Per elsewhere in this file, we can remove the listener once we will have no further purpose for it.
             if (!this.shouldShowSentReceipt && !this.shouldShowSendingReceipt) {
-                this.context.removeListener("Room.receipt", this.onRoomReceipt);
+                MatrixClientPeg.get().removeListener("Room.receipt", this.onRoomReceipt);
                 this.isListeningForReceipts = false;
             }
         });
@@ -779,9 +763,9 @@ export default class EventTile extends React.Component<IProps, IState> {
             return;
         }
 
-        const encryptionInfo = this.context.getEventEncryptionInfo(mxEvent);
+        const encryptionInfo = MatrixClientPeg.get().getEventEncryptionInfo(mxEvent);
         const senderId = mxEvent.getSender();
-        const userTrust = this.context.checkUserTrust(senderId);
+        const userTrust = MatrixClientPeg.get().checkUserTrust(senderId);
 
         if (encryptionInfo.mismatchedSender) {
             // something definitely wrong is going on here
@@ -799,7 +783,7 @@ export default class EventTile extends React.Component<IProps, IState> {
             return;
         }
 
-        const eventSenderTrust = encryptionInfo.sender && this.context.checkDeviceTrust(
+        const eventSenderTrust = encryptionInfo.sender && MatrixClientPeg.get().checkDeviceTrust(
             senderId, encryptionInfo.sender.deviceId,
         );
         if (!eventSenderTrust) {
@@ -878,14 +862,16 @@ export default class EventTile extends React.Component<IProps, IState> {
 
     private shouldHighlight(): boolean {
         if (this.props.forExport) return false;
-        if (this.props.tileShape === TileShape.Notif) return false;
-        if (this.props.tileShape === TileShape.ThreadPanel) return false;
+        if (this.context.timelineRenderingType === TimelineRenderingType.Notification) return false;
+        if (this.context.timelineRenderingType === TimelineRenderingType.ThreadsList) return false;
 
-        const actions = this.context.getPushActionsForEvent(this.props.mxEvent.replacingEvent() || this.props.mxEvent);
+        const actions = MatrixClientPeg.get().getPushActionsForEvent(
+            this.props.mxEvent.replacingEvent() || this.props.mxEvent,
+        );
         if (!actions || !actions.tweaks) { return false; }
 
         // don't show self-highlights from another of our clients
-        if (this.props.mxEvent.getSender() === this.context.credentials.userId) {
+        if (this.props.mxEvent.getSender() === MatrixClientPeg.get().credentials.userId) {
             return false;
         }
 
@@ -1013,7 +999,7 @@ export default class EventTile extends React.Component<IProps, IState> {
         // Cancel any outgoing key request for this event and resend it. If a response
         // is received for the request with the required keys, the event could be
         // decrypted successfully.
-        this.context.cancelAndResendEventRoomKeyRequest(this.props.mxEvent);
+        MatrixClientPeg.get().cancelAndResendEventRoomKeyRequest(this.props.mxEvent);
     };
 
     private onPermalinkClicked = e => {
@@ -1054,7 +1040,7 @@ export default class EventTile extends React.Component<IProps, IState> {
             }
         }
 
-        if (this.context.isRoomEncrypted(ev.getRoomId())) {
+        if (MatrixClientPeg.get().isRoomEncrypted(ev.getRoomId())) {
             // else if room is encrypted
             // and event is being encrypted or is not_sent (Unknown Devices/Network Error)
             if (ev.status === EventStatus.ENCRYPTING) {
@@ -1169,7 +1155,10 @@ export default class EventTile extends React.Component<IProps, IState> {
         const isEncryptionFailure = this.props.mxEvent.isDecryptionFailure();
 
         let isContinuation = this.props.continuation;
-        if (this.props.tileShape && this.props.layout !== Layout.Bubble) {
+        if (this.context.timelineRenderingType !== TimelineRenderingType.Room &&
+            this.context.timelineRenderingType !== TimelineRenderingType.Search &&
+            this.props.layout !== Layout.Bubble
+        ) {
             isContinuation = false;
         }
 
@@ -1196,7 +1185,7 @@ export default class EventTile extends React.Component<IProps, IState> {
             mx_EventTile_bad: isEncryptionFailure,
             mx_EventTile_emote: msgtype === MsgType.Emote,
             mx_EventTile_noSender: this.props.hideSender,
-            mx_EventTile_clamp: this.props.tileShape === TileShape.ThreadPanel,
+            mx_EventTile_clamp: this.context.timelineRenderingType === TimelineRenderingType.ThreadsList,
             mx_EventTile_noBubble: noBubbleEvent,
         });
 
@@ -1219,7 +1208,9 @@ export default class EventTile extends React.Component<IProps, IState> {
         let avatarSize;
         let needsSenderProfile;
 
-        if (this.props.tileShape === TileShape.Notif || this.props.tileShape === TileShape.ThreadPanel) {
+        if (this.context.timelineRenderingType === TimelineRenderingType.Notification ||
+            this.context.timelineRenderingType === TimelineRenderingType.ThreadsList
+        ) {
             avatarSize = 24;
             needsSenderProfile = true;
         } else if (tileHandler === 'messages.RoomCreate' || isBubbleMessage) {
@@ -1234,7 +1225,7 @@ export default class EventTile extends React.Component<IProps, IState> {
             avatarSize = 14;
             needsSenderProfile = true;
         } else if (
-            (this.props.continuation && this.props.tileShape !== TileShape.FileGrid) ||
+            (this.props.continuation && this.context.timelineRenderingType !== TimelineRenderingType.File) ||
             eventType === EventType.CallInvite
         ) {
             // no avatar or sender profile for continuation messages and call tiles
@@ -1269,17 +1260,20 @@ export default class EventTile extends React.Component<IProps, IState> {
         }
 
         if (needsSenderProfile && this.props.hideSender !== true) {
-            if (!this.props.tileShape || this.props.tileShape === TileShape.Thread) {
-                sender = <SenderProfile onClick={this.onSenderProfileClick}
+            if (this.context.timelineRenderingType === TimelineRenderingType.Room ||
+                this.context.timelineRenderingType === TimelineRenderingType.Search ||
+                this.context.timelineRenderingType === TimelineRenderingType.Pinned ||
+                this.context.timelineRenderingType === TimelineRenderingType.Thread
+            ) {
+                sender = <SenderProfile
+                    onClick={this.onSenderProfileClick}
                     mxEvent={this.props.mxEvent}
                     enableFlair={this.props.enableFlair}
-                    tileShape={this.props.tileShape}
                 />;
             } else {
                 sender = <SenderProfile
                     mxEvent={this.props.mxEvent}
                     enableFlair={this.props.enableFlair}
-                    tileShape={this.props.tileShape}
                 />;
             }
         }
@@ -1303,16 +1297,16 @@ export default class EventTile extends React.Component<IProps, IState> {
             || this.state.hover
             || this.state.actionBarFocused);
 
-        const room = this.context.getRoom(this.props.mxEvent.getRoomId());
+        const room = MatrixClientPeg.get().getRoom(this.props.mxEvent.getRoomId());
         const thread = room?.findThreadForEvent?.(this.props.mxEvent);
 
         // Thread panel shows the timestamp of the last reply in that thread
-        const ts = this.props.tileShape !== TileShape.ThreadPanel
+        const ts = this.context.timelineRenderingType !== TimelineRenderingType.ThreadsList
             ? this.props.mxEvent.getTs()
             : thread?.replyToEvent.getTs();
 
         const messageTimestamp = <MessageTimestamp
-            showRelative={this.props.tileShape === TileShape.ThreadPanel}
+            showRelative={this.context.timelineRenderingType === TimelineRenderingType.ThreadsList}
             showTwelveHour={this.props.isTwelveHour}
             ts={ts}
         />;
@@ -1392,7 +1386,7 @@ export default class EventTile extends React.Component<IProps, IState> {
             msgOption = readAvatars;
         }
 
-        const renderTarget = this.props.tileShape === TileShape.Thread
+        const renderTarget = this.context.timelineRenderingType === TimelineRenderingType.Thread
             ? RelationType.Thread
             : undefined;
 
@@ -1412,11 +1406,11 @@ export default class EventTile extends React.Component<IProps, IState> {
             />
             : null;
 
-        const isOwnEvent = this.props.mxEvent?.sender?.userId === this.context.getUserId();
+        const isOwnEvent = this.props.mxEvent?.sender?.userId === MatrixClientPeg.get().getUserId();
 
-        switch (this.props.tileShape) {
-            case TileShape.Notif: {
-                const room = this.context.getRoom(this.props.mxEvent.getRoomId());
+        switch (this.context.timelineRenderingType) {
+            case TimelineRenderingType.Notification: {
+                const room = MatrixClientPeg.get().getRoom(this.props.mxEvent.getRoomId());
                 return React.createElement(this.props.as || "li", {
                     "className": classes,
                     "aria-live": ariaLive,
@@ -1443,7 +1437,6 @@ export default class EventTile extends React.Component<IProps, IState> {
                             highlightLink={this.props.highlightLink}
                             showUrlPreview={this.props.showUrlPreview}
                             onHeightChanged={this.props.onHeightChanged}
-                            tileShape={this.props.tileShape}
                             editState={this.props.editState}
                             getRelationsForEvent={this.props.getRelationsForEvent}
                             isSeeingThroughMessageHiddenForModeration={isSeeingThroughMessageHiddenForModeration}
@@ -1451,8 +1444,8 @@ export default class EventTile extends React.Component<IProps, IState> {
                     </div>,
                 ]);
             }
-            case TileShape.Thread: {
-                const room = this.context.getRoom(this.props.mxEvent.getRoomId());
+            case TimelineRenderingType.Thread: {
+                const room = MatrixClientPeg.get().getRoom(this.props.mxEvent.getRoomId());
                 return React.createElement(this.props.as || "li", {
                     "ref": this.ref,
                     "className": classes,
@@ -1485,7 +1478,6 @@ export default class EventTile extends React.Component<IProps, IState> {
                             highlightLink={this.props.highlightLink}
                             showUrlPreview={this.props.showUrlPreview}
                             onHeightChanged={this.props.onHeightChanged}
-                            tileShape={this.props.tileShape}
                             editState={this.props.editState}
                             replacingEventId={this.props.replacingEventId}
                             getRelationsForEvent={this.props.getRelationsForEvent}
@@ -1497,7 +1489,7 @@ export default class EventTile extends React.Component<IProps, IState> {
                     reactionsRow,
                 ]);
             }
-            case TileShape.ThreadPanel: {
+            case TimelineRenderingType.ThreadsList: {
                 // tab-index=-1 to allow it to be focusable but do not add tab stop for it, primarily for screen readers
                 return (
                     React.createElement(this.props.as || "li", {
@@ -1508,7 +1500,7 @@ export default class EventTile extends React.Component<IProps, IState> {
                         "aria-atomic": "true",
                         "data-scroll-tokens": scrollToken,
                         "data-layout": this.props.layout,
-                        "data-shape": this.props.tileShape,
+                        "data-shape": this.context.timelineRenderingType,
                         "data-self": isOwnEvent,
                         "data-has-reply": !!replyChain,
                         "data-notification": this.state.threadNotification,
@@ -1550,7 +1542,7 @@ export default class EventTile extends React.Component<IProps, IState> {
                     </>)
                 );
             }
-            case TileShape.FileGrid: {
+            case TimelineRenderingType.File: {
                 return React.createElement(this.props.as || "li", {
                     "className": classes,
                     "aria-live": ariaLive,
@@ -1563,7 +1555,6 @@ export default class EventTile extends React.Component<IProps, IState> {
                             highlights={this.props.highlights}
                             highlightLink={this.props.highlightLink}
                             showUrlPreview={this.props.showUrlPreview}
-                            tileShape={this.props.tileShape}
                             onHeightChanged={this.props.onHeightChanged}
                             editState={this.props.editState}
                             getRelationsForEvent={this.props.getRelationsForEvent}
@@ -1584,7 +1575,7 @@ export default class EventTile extends React.Component<IProps, IState> {
                 ]);
             }
 
-            default: {
+            default: { // Pinned, Room, Search
                 // tab-index=-1 to allow it to be focusable but do not add tab stop for it, primarily for screen readers
                 return (
                     React.createElement(this.props.as || "li", {
diff --git a/src/components/views/rooms/PinnedEventTile.tsx b/src/components/views/rooms/PinnedEventTile.tsx
index 8f45039cf2..91ad97236a 100644
--- a/src/components/views/rooms/PinnedEventTile.tsx
+++ b/src/components/views/rooms/PinnedEventTile.tsx
@@ -30,7 +30,6 @@ import { replaceableComponent } from "../../../utils/replaceableComponent";
 import MatrixClientContext from "../../../contexts/MatrixClientContext";
 import { getUserNameColorClass } from "../../../utils/FormattingUtils";
 import AccessibleTooltipButton from "../elements/AccessibleTooltipButton";
-import { TileShape } from "./EventTile";
 import { ViewRoomPayload } from "../../../dispatcher/payloads/ViewRoomPayload";
 
 interface IProps {
@@ -92,7 +91,6 @@ export default class PinnedEventTile extends React.Component<IProps> {
                     className="mx_PinnedEventTile_body"
                     maxImageHeight={150}
                     onHeightChanged={() => {}} // we need to give this, apparently
-                    tileShape={TileShape.Pinned}
                 />
             </div>
 
diff --git a/src/contexts/RoomContext.ts b/src/contexts/RoomContext.ts
index 7e838d1ac9..e20ae0848b 100644
--- a/src/contexts/RoomContext.ts
+++ b/src/contexts/RoomContext.ts
@@ -25,7 +25,8 @@ export enum TimelineRenderingType {
     ThreadsList = "ThreadsList",
     File = "File",
     Notification = "Notification",
-    Search = "Search"
+    Search = "Search",
+    Pinned = "Pinned",
 }
 
 const RoomContext = createContext<IRoomState>({