---
title: "Tasks and Events: one object, two behaviours"
url: "https://trailassembly.com/activities-tasks-and-events/"
topic: "Admin and Permissions"
published: "2026-09-15T04:18:40+00:00"
updated: "2026-10-06T13:55:30+00:00"
---

# Tasks and Events: one object, two behaviours

**Task and Event are two separate objects that share one set of custom fields, one pair of polymorphic lookups, and one confusing name.** You cannot query Activity. You can report on both together in places. Almost every hard question about activity data comes back to the two polymorphic fields, `WhoId` and `WhatId`.

## Two objects, one field set

Task and Event are distinct objects with their own API names, triggers and page layouts. What they share is the Activity object in Setup: add a custom field there and it appears on both. Adding a field to only one of them means going to that object directly, which people forget is possible.

The difference between them is time. An Event has a start and an end and lives on a calendar. A Task has a due date and a status. Meetings with a duration are Events. Everything else is a Task. Orgs that log calls as Events end up with a calendar full of things that never happened at a time.

## WhoId and WhatId

`WhoId` points at a Lead or a Contact. `WhatId` points at an Account, Opportunity, Case, Campaign, Contract, or any custom object with Allow Activities enabled.

Two rules matter. A record with a Lead in `WhoId` cannot have a `WhatId`, because leads do not have related records to relate to. And `WhatId` holds exactly one Id, so a call about three opportunities is logged against one of them or against the account.

Shared Activities, in Activity Settings, lets one activity relate to several contacts through TaskRelation and EventRelation. `WhoId` then holds the primary contact and the rest live in relation records. It is a one-way setting, and reporting afterwards needs the relation object rather than `WhoId` to be complete.

## Querying polymorphic lookups

You cannot dot-walk from `WhatId` to fields on a parent, because the platform does not know which parent. SOQL gives you `TYPEOF`:

```apex
SELECT Id, Subject, ActivityDate,
       TYPEOF What
         WHEN Opportunity THEN StageName, Amount
         WHEN Account THEN Industry
         ELSE Name
       END
FROM Task
WHERE ActivityDate = LAST_N_DAYS:30
```

The alternative is querying `WhatId`, splitting the Ids by [key prefix](https://trailassembly.com/salesforce-record-id-behaviour/) and querying each object separately. More code, predictable behaviour, which is why most integrations do it that way.

## The roll-up fields

Account, Contact, Lead and Opportunity carry `LastActivityDate`, maintained by the platform from the most recent completed task or past event. It finds stale accounts well, and a future-dated open task does not set it, so it reflects work done rather than work planned.

There is no standard activity count. Counting per account means a roll-up you build, and building it correctly means handling the polymorphic parent, which is why so many orgs have a half-finished one.

ActivityHistory and OpenActivity are read-only related objects you can only reach as subqueries from a parent record. They are how the related lists work, and they are queryable:

```apex
SELECT Id, Name,
       (SELECT Subject, ActivityDate FROM OpenActivities),
       (SELECT Subject, ActivityDate FROM ActivityHistories)
FROM Account WHERE Id = :accountId
```

They cannot be the main object of a query and they return a limited number of rows, so they are a display mechanism rather than a reporting one.

## Why reporting is hard

A short list of the reasons, because each one surprises someone:

- Standard report types cover Tasks and Events together, or activities with one specific parent object. A single report showing all activity across accounts and opportunities with fields from both parents is not available.

- Activity data is archived after roughly a year, and archived records drop out of standard reports and list views unless you go looking for them.

- Email logged through integrations may land as a Task, an EmailMessage, or nowhere in Salesforce at all, depending on the tool. Activity reports then measure your integration rather than your team.

- Recurring events expand into multiple records, so event counts inflate for anything with a weekly series.

The practical answer for serious activity analytics is to stop reporting on the raw objects. A nightly job that flattens activities into a custom object with a resolved parent account, a normalised type and a real user reference gives you something reportable, and it costs one batch class.

## Frequently asked

**Can a custom object hold activities?** Only with Allow Activities ticked on the object definition. It cannot be turned off cleanly once records exist.

**Do tasks have [record types](https://trailassembly.com/record-types/)?** Yes, and Events do too. They are separate from each other despite the shared field set.

**Why is an activity missing from the account?** Its `WhatId` points at the opportunity, not the account. Related lists on the account do show activities from child opportunities in some configurations, which is why this is confusing rather than simply wrong.

**Can I trigger on Activity?** No, write triggers on Task and Event separately.

---

Source: https://trailassembly.com/activities-tasks-and-events/
Trail Assembly — independent Salesforce write-ups.
