---
title: 'CHR0049: [EventTypeGenerationFor<T>] must reference a type marked with [EventType]'
---

import { Tabs, TabItem } from '@astrojs/starlight/components';

## Rule Description

`[EventTypeGenerationFor<T>]` marks a record as a previous generation of the event type `T` represents. Chronicle resolves the shared event type id directly from `T`'s own `[EventType]` attribute — so `T` must carry `[EventType]` directly.

This is reported whenever `T`:

- has no `[EventType]` attribute at all, or
- is itself marked with `[EventTypeGenerationFor<T>]` instead — chaining generation markers is rejected for the same reason: there is still no `[EventType]` at the end of the chain to resolve an id from.

## Severity

Error

## Example

### Violation

<Tabs syncKey="chronicle-client">
<TabItem label="C#">

```csharp
using Cratis.Chronicle.Events;

public record Chr0049ViolationCustomerRegisteredV2(string FirstName, string LastName);

// Error CHR0049: 'Chr0049ViolationCustomerRegisteredV1' declares itself as a generation for
// 'Chr0049ViolationCustomerRegisteredV2', but 'Chr0049ViolationCustomerRegisteredV2' is not
// marked with [EventType].
[EventTypeGenerationFor<Chr0049ViolationCustomerRegisteredV2>(1)]
public record Chr0049ViolationCustomerRegisteredV1(string Name);
```

</TabItem>
</Tabs>

### Fix

<Tabs syncKey="chronicle-client">
<TabItem label="C#">

```csharp
using Cratis.Chronicle.Events;

[EventType("customer-registered", generation: 2)]
public record Chr0049FixCustomerRegisteredV2(string FirstName, string LastName);

[EventTypeGenerationFor<Chr0049FixCustomerRegisteredV2>(1)]
public record Chr0049FixCustomerRegisteredV1(string Name);
```

</TabItem>
</Tabs>

## Why This Rule Exists

`[EventTypeGenerationFor<T>]` exists so a previous-generation record never carries its own, independently-typed event type id — the id comes from `T` instead, so the two can never drift apart. That only works if `T` actually has an id to give: a type with no `[EventType]` attribute has none, and neither does a type that is itself only a generation marker.

Without this check, a record marked `[EventTypeGenerationFor<T>]` where `T` isn't an event type compiles cleanly but fails only when the client connects to Chronicle, throwing `EventTypeGenerationReferencesNonEventType` at startup. This rule surfaces the same mistake at compile time instead.

The same analyzer class also reports **CHR0050** (`EventTypeGenerationForCannotCombineWithEventType`, Error) when a type carries both `[EventType]` and `[EventTypeGenerationFor<T>]` at once. A type is either the current generation or a previous one — never both — and combining them throws `EventTypeGenerationForCannotBeCombinedWithEventType` at runtime for the same reason this rule's violation does: Chronicle can no longer tell which attribute owns the id.

## Related Rules

- [CHR0037](/chronicle/code-analysis/chr0037/): Event type migration generations must belong to one event type — validates that a migration's `[EventTypeGenerationFor<T>]` points at the migration's own upgrade type, once it already resolves to an event type.
