class ClientEvent(AffectiveEvent, ClientIdMixin):
     'To affect Client identified by ClientIdMixin.'
 
+    @classmethod
+    def make_subtype(cls, method_to_call: str, **kwargs
+                     ) -> type['ClientEvent']:
+        'Return subclass whose .affect calls method_to_call on target, kwargs.'
+        class _AdaptedEvent(ClientEvent):
+            def affect(self, target) -> None:
+                getattr(target, method_to_call)(**kwargs)
+        return _AdaptedEvent
+
 
 class _IrcConnection(BaseIrcConnection):
 
         super().__init__(**kwargs)
 
     def _make_recv_event(self, msg: IrcMessage) -> ClientEvent:
-
-        @dataclass
-        class _RecvEvent(ClientEvent, PayloadMixin):
-            payload: IrcMessage
-
-            def affect(self, target: 'Client') -> None:
-                target.handle_msg(self.payload)
-
-        return _RecvEvent(client_id=self.client_id, payload=msg)
+        return ClientEvent.make_subtype(method_to_call='handle_msg', msg=msg)(
+                client_id=self.client_id)
 
 
 @dataclass
         'Start thread to set up _IrcConnection at .conn.'
 
         def connect(self) -> None:
-
-            @dataclass
-            class _ConnectedEvent(ClientEvent):
-                def affect(self, target: 'Client') -> None:
-                    target.on_connect()
-
             try:
                 self.conn = _IrcConnection(hostname=self.conn_setup.hostname,
                                            q_out=self.q_out,
                                            client_id=self.id_)
-                self._cput(_ConnectedEvent)
+                self._cput(ClientEvent.make_subtype('on_connect'))
             except IrcConnAbortException as e:
                 self.log(f'# ALERT: {e}')
             except Exception as e:  # pylint: disable=broad-exception-caught