diff --git a/osu.Desktop/LegacyIpc/LegacyIpcMessage.cs b/osu.Desktop/LegacyIpc/LegacyIpcMessage.cs
index 6fefae4509..0fa60e2068 100644
--- a/osu.Desktop/LegacyIpc/LegacyIpcMessage.cs
+++ b/osu.Desktop/LegacyIpc/LegacyIpcMessage.cs
@@ -2,11 +2,24 @@
// See the LICENCE file in the repository root for full licence text.
using osu.Framework.Platform;
+using Newtonsoft.Json.Linq;
namespace osu.Desktop.LegacyIpc
{
///
/// An that can be used to communicate to and from legacy clients.
+ ///
+ /// In order to deserialise types at either end, types must be serialised as their ,
+ /// however this cannot be done since osu!stable and osu!lazer live in two different assemblies.
+ ///
+ /// To get around this, this class exists which serialises a payload () as an type,
+ /// which can be deserialised at either end because it is part of the core library (mscorlib / System.Private.CorLib).
+ /// The payload contains the data to be sent over the IPC channel.
+ ///
+ /// At either end, Json.NET deserialises the payload into a which is manually converted back into the expected type,
+ /// which then further contains another representing the data sent over the IPC channel whose type can likewise be lazily matched through
+ /// .
+ ///
///
///
/// Synchronise any changes with osu-stable.
diff --git a/osu.Desktop/LegacyIpc/LegacyTcpIpcProvider.cs b/osu.Desktop/LegacyIpc/LegacyTcpIpcProvider.cs
index e42a10430a..97a4c57bf0 100644
--- a/osu.Desktop/LegacyIpc/LegacyTcpIpcProvider.cs
+++ b/osu.Desktop/LegacyIpc/LegacyTcpIpcProvider.cs
@@ -36,6 +36,7 @@ namespace osu.Desktop.LegacyIpc
logger.Add("Processing legacy IPC message...");
logger.Add($" {msg.Value}", LogLevel.Debug);
+ // See explanation in LegacyIpcMessage for why this is done this way.
var legacyData = ((JObject)msg.Value).ToObject();
object value = parseObject((JObject)legacyData!.MessageData, legacyData.MessageType);